Разве несколько потоков не могут одновременно войти в синхронизированный блок?
Я новичок в Java и наткнулся на эту ссылку: http://tutorials.jenkov.com/java-concurrency/slipped-conditions.html, понимая многопоточность в Java.
В этом руководстве приведенный ниже код называется хорошей практикой, позволяющей избежать проскальзывания:
public class Lock {
private boolean isLocked = true;
public void lock(){
synchronized(this){
while(isLocked){
try{
this.wait();
} catch(InterruptedException e){
//do nothing, keep waiting
}
}
isLocked = true;
}
}
public synchronized void unlock(){
isLocked = false;
this.notify();
}
}
Я сомневаюсь, что в случае, когда два потока A & B вызывают lock() одновременно и isLocked имеет значение true, т.е. блокировка была взята другим потоком C. Теперь:
--1 A сначала входит в синхронизированный блок (поскольку только один может получить блокировку для объекта-монитора this и войти в синхронизированный блок) --2 A вызывает this.wait() и, таким образом, снимает блокировку с объекта-монитора this (wait() снимает блокировку на объекте монитора http://tutorials.jenkov.com/java-concurrency/thread-signaling.html), но остается внутри синхронизированного блока -3 Теперь B входит в синхронизированный блок (так как A снял блокировку для объекта-монитора this) --4 B вызывает this.wait() и, таким образом, снимает блокировку для объекта-монитора this (вызов wait () освобождает блокировку для объекта-монитора) --5 в этот момент поток C вызывает unlock() т.е. устанавливает isLocked в false и вызывает this.notify() --6 Теперь один из A и B выходит из wait(), затем выходит из цикла while и устанавливает isLocked в true --7, и цикл продолжается
Таким образом, в -3 и A, и B находятся в синхронизированном блоке одновременно, не является ли это нарушением основного принципа многопоточности, что в синхронизированном блоке одновременно может быть разрешен только один поток?
Пожалуйста, проясните мои сомнения.
1 ответ
Поток может возвращаться из метода wait() только в том случае, если он вновь получает блокировку для объекта, на котором он ожидает. В вашем сценарии A и B будут бороться за блокировку, только один из них получит ее, а другой будет ждать, пока блокировка не будет снята снова.
От Javadoc (выделение мое):
Текущий поток должен владеть монитором этого объекта. Поток освобождает владельца этого монитора и ожидает, пока другой поток не уведомит потоки, ожидающие на мониторе этого объекта, чтобы он проснулся либо посредством вызова метода notify, либо метода notifyAll. Затем поток ожидает, пока не получит право владения монитором, и возобновит выполнение.