Antecedentes:
O que é "reentrante"? Reentrante significa que um encadeamento adquiriu um bloqueio e pode adquiri-lo novamente sem um conflito. O objetivo dos bloqueios reentrantes é evitar bloqueios.Os sincronizados e ReentrantLock em Java são bloqueios reentrantes.
// bloqueio de reentrada sincronizada private void test () { // adquire o bloqueio pela primeira vez sincronizado ( this ) { while ( true ) { // adquire o mesmo bloqueio pela segunda vez sincronizado ( this ) { System.out.println ( "ReentrantLock!" ); } Tente { Thread.sleep ( 1000 ); } catch (InterruptedException e) { e.printStackTrace (); } } } } // ReentrantLock 锁 重 入 lock Lock lock = new ReentrantLock (); private void test1 () { lock.lock (); tente { test2 (); } finalmente { lock.unlock (); } } private void test2 () { lock.lock (); tente { System.out.println ( "ReentrantLock!" ); } finalmente { lock.unlock (); } }
1. Bloqueio não reentrante personalizado
O chamado bloqueio não reentrante, ou seja, se o encadeamento atual executar um método que já adquiriu o bloqueio, quando o método tentar adquirir o bloqueio novamente, ele não será bloqueado. O segmento a seguir executa o método test1 () para adquirir o bloqueio primeiro e, em seguida, executa o método test2 () para não executar a lógica em test2 () .O bloqueio deve ser liberado primeiro.
// Classe de bloqueio não reentrada Lock { // Se o booleano privado isLocked = false ; // Use lock público sincronizado void lock () { while (isLocked) {// Já ocupado, tente { this .wait (); // Aguardando } catch (InterruptedException e) { e.printStackTrace (); } } isLocked = true ; // Modifica o sinalizador conforme ocupado } // Libera o bloqueio público sincronizado void unLock () { isLocked = false ; // Modifica o sinalizador como desocupado notify (); // Desperta o thread em espera } } ============ Use ========== = Lock lock = new Lock (); public void test1 () { lock.lock (); test2 (); lock.unLock (); } private void test2 () { lock.lock (); // ... lock .unLock (); }
2. Bloqueio reentrante personalizado
Processo:
- Defina o número de identificadores de ocupação de bloqueio, threads de armazenamento e bloqueios de thread retidos;
- Usar bloqueio: determine se está ocupado e se o encadeamento atual não é igual ao encadeamento de armazenamento, se as condições atenderem à entrada aguardar, se não atender, modifique o sinalizador de ocupação, o encadeamento de armazenamento é o encadeamento atual, o número de bloqueios de encadeamento +1;
- Libere o bloqueio: determine se o encadeamento atual é igual ao encadeamento de armazenamento, o número de bloqueios de encadeamento é -1 quando as condições forem atendidas, quando o número de bloqueios de encadeamento = 0, modifique o sinalizador de ocupação, ative o encadeamento em espera e defina o encadeamento de armazenamento como nulo;
// 可重入锁 classe relock { // 是否占用 private boolean isLocked = false ; segmento privado lockedBy = null ; // 存储线程 privada int holdCount = 0 ; // 使用锁 pública sincronizado vazio lock () lança InterruptedException { Tópico t = Thread.currentThread (); while (isLocked && lockedBy! = t) { wait (); } isLocked = true; lockedBy = t; holdCount ++ ; } // unlock 锁 desbloqueio público anulado sincronizado () { if (Thread.currentThread () == lockedBy) { holdCount - ; if (holdCount == 0 ) { isLocked = false ; notify (); lockedBy = null ; } } } Público int getHoldCount () { return holdCount; } } ============== class =============== classe pública LockTest { ReLock lock = new ReLock (); public void test1 () lança InterruptedException { lock.lock (); System.out.println (lock.getHoldCount ()); test2 (); bloquear desbloquear(); System.out.println (lock.getHoldCount ()); } // 入 重 入public void test2 () lança InterruptedException { lock.lock (); System.out.println (lock.getHoldCount ()); // ................... lock.unlock (); System.out.println (lock.getHoldCount ()); } public static void main (String [] args) lança InterruptedException { LockTest lockTest = new LockTest (); lockTest.test1 (); Thread.sleep ( 1000 ); System.out.println (lockTest.lock.getHoldCount ()); } }