prefácio
artigo anteriorCondição da Programação Simultânea Java (1)O processo de implementação do método é apresentado await
, e os seguintes pontos precisam ser focados:
- Se o método for chamado primeiro
interrupt
, chamar await lançará diretamente uma exceção; await
Método elock
método possuem uma fila de espera respectivamente;interrupt
esignal
pode acordar threads de esperaawait
dele .
Este artigo apresenta principalmente o seguinte signal
processo de execução do código-fonte:
sinal
// 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();
}
复制代码
Ao chamar signal
o método, ele primeiro verificará se a thread atual é uma thread segurando um bloqueio. Caso contrário, ela não poderá ser ativada e uma exceção será lançada diretamente. Em seguida, obtenha o nó principal null
e ative-o se não for o nó principal.
signal
O método precisa ser chamado após adquirir o bloqueio, caso contrário,IllegalMonitorStateException
uma exceção é lançada
private void doSignal(Node first) {
do {
if ( (firstWaiter = first.nextWaiter) == null)
lastWaiter = null;
first.nextWaiter = null;
} while (!transferForSignal(first) &&
(first = firstWaiter) != null);
}
复制代码
Ativar o nó principal precisa removê-lo da fila de espera condicional. A instrução if acima primeiro aponta o nó principal para o próximo bit. Se o próximo bit for, significa que não há nenhum nó na fila, então defina o nó null
final nó para null
, e o nó principal O próximo nó do nó é naturalmente também null
.
while
A condição de loop significa que, se o nó principal atual falhar ao alternar da fila de espera condicional para a fila síncrona, e o próximo nó não for, ative o próximo nó null
até que um nó bem-sucedido seja ativado ou toda a fila seja percorrida.
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;
}
复制代码
O nó é convertido da fila de espera condicional para a fila de sincronização. Primeiro, por meio CAS
da modificação waitStatus
, se for bem-sucedido, enq
o nó pode ser adicionado ao final da fila de sincronização por meio do método e o nó predecessor é retornado.
Como os nós na fila de sincronização precisam ser ativados pelo nó predecessor, se o nó predecessor for cancelado ( waitStatus>0
) ou waitStatus
modificado para Node.SIGNAL
( -1
) falhar, isso significa que o nó anterior não pode ativar o thread atual, portanto, neste momento, diretamente use unpark
o método para ativar o thread atual, para evitar que nunca seja ativado.
Resumir
signal
O processo do método await
é muito mais simples que o método, e faz principalmente duas coisas:
- Remova o nó do thread atual da fila de condições;
- Adicione o nó do encadeamento atual ao final da fila de bloqueio síncrono.