JAVA鎖之wait,notify(wait會釋放鎖,notify僅僅只是通知,不釋放鎖)


wait是指在一個已經進入了同步鎖的線程內,讓自己暫時讓出同步鎖,以便其他正在等待此鎖的線程可以得到同步鎖並運行,只有其他線程調用了notify方法(notify並不釋放鎖,只是告訴調用過wait方法的線程可以去參與獲得鎖的競爭了,但不是馬上得到鎖,因為鎖還在別人手里,別人還沒釋放),調用wait方法的一個或多個線程就會解除wait狀態,重新參與競爭對象鎖,程序如果可以再次得到鎖,就可以繼續向下運行。

1)wait()、notify()和notifyAll()方法是本地方法,並且為final方法,無法被重寫。

 2)當前線程必須擁有此對象的monitor(即鎖),才能調用某個對象的wait()方法能讓當前線程阻塞,

(這種阻塞是通過提前釋放synchronized鎖,重新去請求鎖導致的阻塞,這種請求必須有其他線程通過notify()或者notifyAll()喚醒重新競爭獲得鎖)

 3)調用某個對象的notify()方法能夠喚醒一個正在等待這個對象的monitor的線程,如果有多個線程都在等待這個對象的monitor,則只能喚醒其中一個線程;

(notify()或者notifyAll()方法並不是真正釋放鎖,必須等到synchronized方法或者語法塊執行完才真正釋放鎖)

 4)調用notifyAll()方法能夠喚醒所有正在等待這個對象的monitor的線程,喚醒的線程獲得鎖的概率是隨機的,取決於cpu調度

例子1(錯誤使用導致線程阻塞):三個線程,線程3先擁有sum對象的鎖,然后通過sum.notify()方法通知等待sum鎖的線程去獲得鎖,但是這個時候線程1,2並沒有處於wait()導致的阻塞狀態,而是在synchronized方法塊處阻塞了,所以,這次notify()根本沒有通知到線程1,2。然后線程3正常結束,釋放掉sum鎖,這個時候,線程1就立刻獲得了sum對象的鎖(通過synchronized獲得),然后調用sum.wait()方法釋放掉sum的鎖,線程2隨后獲得了sum對象的線程鎖(通過synchronized獲得),這個時候線程1,2都處於阻塞狀態,但是悲催的是,這之后再也沒有線程主動調用sum.notify()或者notifyAll()方法顯示喚醒這兩個線程,所以程序阻塞

public class CyclicBarrierTest {  
public static void main(String[] args) throws Exception {  
    final Sum sum=new Sum();  
      
    new Thread(new Runnable() {  
        @Override  
        public void  run() {  
            try {  
                synchronized (sum) {  
                    System.out.println("thread3 get lock");  
                    sum.sum();  
                    sum.notifyAll(); //此時喚醒沒有作用,沒有線程等待  
                    Thread.sleep(2000);  
                    System.out.println("thread3 really release lock");  
                }  
                  
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
        }  
    }).start();  
      
    new Thread(new Runnable() {  
        @Override  
        public void  run() {  
            try {  
                synchronized (sum) {  
                    System.out.println("thread1 get lock");  
                    sum.wait();//主動釋放掉sum對象鎖  
                    System.out.println(sum.total);  
                    System.out.println("thread1 release lock");  
                }  
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
        }  
    }).start();  
      
    new Thread(new Runnable() {  
        @Override  
        public void  run() {  
            try {  
                synchronized (sum) {  
                    System.out.println("thread2 get lock");  
                    sum.wait();  //釋放sum的對象鎖,等待其他對象喚醒(其他對象釋放sum鎖)  
                    System.out.println(sum.total);  
                    System.out.println("thread2 release lock");  
                }  
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
        }  
    }).start();  
}  

}

class Sum{  
public Integer total=0;  
public void  sum() throws Exception{  
    total=100;  
    Thread.sleep(5000);  
}  
  
}  

thread3 get lock  
thread3 really release lock  
thread2 get lock  
thread1 get lock  
//程序后面一直阻塞  

例子2:還是上面程序,順序不同,把線程3放到最下面。最后線程1,2都因為沒有再次獲得線程導致線程阻塞

運行過程:

線程1先運行獲得sum對象鎖(通過synchronized),但是隨后執行了sum.wait()方法,主動釋放掉了sum對象鎖,然后線程2獲得了sum對象鎖(通過synchronized),也通過sum.wait()失去sum的對象鎖,最后線程3獲得了sum對象鎖(通過synchronized),主動通過sum.notify()通知了線程1或者2,假設是1,線程1重新通過notify()/notifyAll()的方式獲得了鎖,然后執行完畢,隨后線程釋放鎖,然后這個時候線程2成功獲得鎖,執行完畢。

public class CyclicBarrierTest {  
public static void main(String[] args) throws Exception {  
    final Sum sum=new Sum();  
      
  
      
    new Thread(new Runnable() {  
        @Override  
        public void  run() {  
            try {  
                synchronized (sum) {  
                    System.out.println("thread1 get lock");  
                    sum.wait();//主動釋放sum對象鎖,等待喚醒  
                    System.out.println(sum.total);  
                    System.out.println("thread1 release lock");  
                }  
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
        }  
    }).start();  
      
    new Thread(new Runnable() {  
        @Override  
        public void  run() {  
            try {  
                synchronized (sum) {  
                    System.out.println("thread2 get lock");  
                    sum.wait();  //主動釋放sum對象鎖,等待喚醒  
                    System.out.println(sum.total);  
                    System.out.println("thread2 release lock");  
                }  
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
        }  
    }).start();  
      
    new Thread(new Runnable() {  
        @Override  
        public void  run() {  
            try {  
                synchronized (sum) {  
                    System.out.println("thread3 get lock");  
                    sum.sum();  
                    sum.notifyAll();//喚醒其他等待線程(線程1,2)  
                    Thread.sleep(2000);  
                    System.out.println("thread3 really release lock");  
                }  
                  
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
        }  
    }).start();  
      
      
    }  
        
}  

class Sum{  
public Integer total=0;  
public void  sum() throws Exception{  
    total=100;  
    Thread.sleep(5000);  
    }  
  
}  

thread1 get lock  
thread2 get lock  
thread3 get lock  
thread3 really release lock  
100  
thread2 release lock  
100  
thread1 release lock 

摘自 https://blog.csdn.net/azhegps/article/details/63031562


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM