A função da condição é fornecer um controle mais preciso da trava. O método Await () na condição é equivalente ao método wait () de objeto, o método Signal () na condição é equivalente ao método notify () de objeto, e o signalall () na condição é equivalente ao método notifyAll () de objeto. A diferença é que os métodos wait (), notify () e notifyAll () no objeto são agrupados com "Lock Sincronizado" (palavra -chave sincronizada); E a condição precisa ser agrupada com "Mutex"/"Share Lock".
Lista de funções de condição
// faz com que o encadeamento atual aguarde até receber um sinal ou ser interrompido. O vazio aguardo () // faz com que o thread atual permaneça em um estado de espera antes de receber um sinal, ser interrompido ou atingir o tempo de espera especificado. Boolean Aguardar (muito tempo, unidade de unidade de tempo) // faz com que o thread atual esteja em um estado de espera até que receba um sinal, seja interrompido ou atinge o tempo de espera especificado. há muito tempo (nanostimeout) // faz com que o thread atual esteja em um estado de espera antes de receber o sinal. O vazio aguarda interruptível () // faz com que o encadeamento atual permaneça em um estado de espera até que receba um sinal, seja interrompido ou atinja o prazo especificado. Boolean Awaituntil (prazo para data) // Acorde um tópico em espera. sinal vazio () // Acorde todos os threads de espera. Void Signalall ()
Exemplo de uso da classe de condição
A condição quebra os métodos de monitor de objetos (aguarde, notificar e notificar todos) em objetos completamente diferentes, para que, ao combinar esses objetos com qualquer implementação de bloqueio, cada objeto forneça vários conjuntos de espera (conjunto de espera). Entre eles, o bloqueio substitui o uso de métodos e declarações sincronizados, e a condição substitui o uso de métodos de monitor de objeto. A seguir, é apresentado um exemplo escrito anteriormente de comunicação de threads com a implementação com a condição, o código é o seguinte:
classe pública threadTest2 {public static void main (string [] args) {Final Business Business = new Business (); novo thread (novo runnable () {@Override public void run () {threadExecute (negócios, "sub");}}). start (); ThreadExecute (Business, "Main"); } public static void threadExecute (negócios de negócios, string threadtype) {for (int i = 0; i <100; i ++) {try {if ("main" .equals (threadtype)) {business.main (i); } else {Business.sub (i); }} catch (interruptEdException e) {e.printStackTrace (); }}}} classe Business {private boolean bool = true; bloqueio privado de bloqueio = new reentrantlock (); condição privada condição = bloqueio.newcondition (); public /*sincronizado* / void main (int loop) lança interruptedException {Lock.lock (); tente {while (bool) {condition.await (); // this.wait (); } para (int i = 0; i <100; i ++) {System.out.println ("Principal seq de thread de" + i + ", loop de" + loop); } bool = true; condicional.signal (); // this.Notify (); } finalmente {Lock.unlock (); }} public /*sincronizado* / void sub (int loop) lança interruptedException {Lock.lock (); tente {while (! bool) {condition.await (); // this.wait (); } para (int i = 0; i <10; i ++) {System.out.println ("Sub Thread seq de" + i + ", loop de" + loop); } bool = false; condicional.signal (); // this.Notify (); } finalmente {Lock.unlock (); }}} Em condição, substitua Wait () pelo AWAIT (), substitua notify () por Signal () e substitua notifyAll () por SignalAll (). O método de comunicação tradicional dos threads pode ser implementado. Observe aqui que a condição está ligada a um bloqueio. Para criar um bloqueio, você deve usar o método newcondition ().
Dessa maneira, a condição não é diferente da comunicação tradicional de threads. O poder da condição é que ela pode estabelecer diferentes condições entre vários threads. A seguir, é apresentado um pedaço de código da API para ilustrar.
Classe BoundedBuffer {Final Lock Lock = new ReentrantLock (); // Bloqueio da condição final Notfull = Lock.Newcondition (); // grava a condição do encadeamento Condição final NotEmpty = Lock.Newcondition (); // Leia a condição de linha Final Object [] itens = novo objeto [100]; // cache de cache int putptr/* fila*/; public void put (objeto x) lança interruptedException {Lock.lock (); tente {while (count == items.length) // Se a fila estiver cheia de notfull.await (); // bloqueia os itens de gravação do thread [putptr] = x; // atribuem se (++ putptr == items.leng) putptr = 0; // se o índice de gravação for escrito para a última posição da fila, definido para 0+. Thread} finalmente {Lock.unlock (); }} public Object Take () lança interruptedException {Lock.lock (); tente {while (count == 0) // se a fila estiver vazia notepty.await (); // bloqueia o objeto de linhas de leitura x = itens [theptr]; // escolha o valor se (++ TakePtr == items.Length) Takeptr = 0; // se o índice de leitura lê a última posição da fila, definida para 0 -0 } finalmente {Lock.unlock (); }}} Esta é uma área de cache em um ambiente de trabalho com vários threads. A área de cache fornece dois métodos: colocar e tomar. A colocação é para armazenar dados, tomar é recuperar dados e há uma fila de cache dentro. Consulte o código para descrições específicas de variáveis e métodos. As funções implementadas por esta classe de área de cache: vários threads armazenam dados e recuperam dados dele. O valor máximo do cache que a fila do cache (primeiro em, primeiro out, depois entra e depois) pode cache ser 100. Vários threads são mutuamente exclusivos. Quando o valor armazenado na fila do cache atingir 100, o thread de gravação será bloqueado e o thread de leitura será despertado. Quando o valor armazenado na fila do cache for 0, o thread de leitura será bloqueado e o thread de gravação será despertado. A análise a seguir do processo de execução de código:
1. Um encadeamento de gravação é executado e chama o método put;
2. Para determinar se a contagem é 100, obviamente não há 100;
3. Continue a executar e depositar o valor;
4. Depois de determinar a posição de índice atualmente escrita ++, seja igual a 100. Equalize o valor do índice de gravação a 0 e contagem+1;
5. Acorde apenas uma das filas de bloqueio de threads de leitura;
6. Execute um thread de leitura e chame o método Take;
7.…
8. Acorde apenas uma das filas de bloqueio de threads de gravação.
Este é o poder de várias condições. Supondo que a fila de cache esteja cheia, o bloqueio é definitivamente o thread de gravação e o despertar é definitivamente o thread de leitura. Pelo contrário, o bloqueio é definitivamente o tópico de leitura, e o despertar é definitivamente o tópico de gravação. Então, o que acontecerá se houver apenas uma condição? A fila de cache está cheia, esse bloqueio não sabe se é o thread de leitura ou o thread de gravação. Se o despertar é o tópico de leitura, todos estão felizes. Se o despertar for o tópico de gravação, o tópico acabou de ser despertado e bloqueado novamente e depois acorda novamente, o que desperdiça muito tempo.