Состояние параллельного программирования на Java (2)

предисловие

предыдущая статьяСостояние параллельного программирования на 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намного проще, чем метод, и в основном он делает две вещи:

  • Удалить узел текущего потока из очереди условий;
  • Добавьте узел текущего потока в конец очереди синхронной блокировки.

Supongo que te gusta

Origin juejin.im/post/7229991597085622328
Recomendado
Clasificación