предисловие
предыдущая статьяСостояние параллельного программирования на Java (1)Вводится процесс реализации метода await
, и необходимо акцентировать внимание на следующих моментах:
- Если метод вызывается первым
interrupt
, то вызов await вызовет прямое исключение; await
Метод иlock
метод имеют очередь ожидания соответственно;interrupt
иsignal
может разбудить ожидающиеawait
от него .
В этой статье в основном представлен следующий signal
процесс выполнения исходного кода:
сигнал
// ConditionObject类
public final void signal() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter;
if (first != null)
doSignal(first);
}
protected final boolean isHeldExclusively() {
return getExclusiveOwnerThread() == Thread.currentThread();
}
复制代码
При вызове signal
метода он сначала проверяет, является ли текущий поток потоком, удерживающим блокировку.Если нет, он не может проснуться, и сразу создается исключение. Затем получите головной узел null
и разбудите его, если это не головной узел.
signal
Метод нужно вызывать после получения блокировки, иначе будет выброшеноIllegalMonitorStateException
исключение
private void doSignal(Node first) {
do {
if ( (firstWaiter = first.nextWaiter) == null)
lastWaiter = null;
first.nextWaiter = null;
} while (!transferForSignal(first) &&
(first = firstWaiter) != null);
}
复制代码
null
Пробуждение головного узла необходимо для его удаления из условной очереди ожидания.Вышеприведенный оператор if сначала указывает головному узлу на следующий бит.Если следующий бит есть, это означает, что в очереди нет узла, поэтому установите хвост узел к null
, и головной узел Следующий узел узла естественно тоже null
.
while
Условие цикла означает, что если текущему головному узлу не удается переключиться из очереди условного ожидания в синхронную очередь, а следующему узлу — нет, то следующий null
узел активируется до тех пор, пока не будет разбужен успешный узел или не будет пройдена вся очередь.
final boolean transferForSignal(Node node) {
if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
return false;
Node p = enq(node);
int ws = p.waitStatus;
if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
LockSupport.unpark(node.thread);
return true;
}
复制代码
Узел преобразуется из условной очереди ожидания в очередь синхронизации.Сначала через CAS
модификацию waitStatus
, в случае успеха, enq
узел может быть добавлен в конец очереди синхронизации через метод, и возвращается узел-предшественник.
Поскольку узлы в очереди синхронизации должны быть пробуждены узлом-предшественником, если узел-предшественник отменен ( waitStatus>0
) или waitStatus
изменен на Node.SIGNAL
( -1
) со сбоем, это означает, что предыдущий узел не может разбудить текущий поток, поэтому в это время непосредственно используйте unpark
метод, чтобы разбудить текущий поток, чтобы никогда не быть разбуженным.
Подведем итог
signal
Процесс метода await
намного проще, чем метод, и в основном он делает две вещи:
- Удалить узел текущего потока из очереди условий;
- Добавьте узел текущего потока в конец очереди синхронной блокировки.