1. 程式人生 > >Java wait、notify與synchronized的奇妙之處

Java wait、notify與synchronized的奇妙之處

一、synchronized是Java語言的關鍵字,當它用來修飾一個方法或者一個程式碼塊的時候,能夠保證在同一時刻最多隻有一個執行緒執行該段程式碼。synchronized就是針對記憶體區塊申請記憶體鎖。
(1)JAVA中的Object型別都是帶有一個記憶體鎖的,在有執行緒獲取該記憶體鎖後,其它執行緒無法訪問該記憶體,從而實現JAVA中簡單的同步、互斥操作。
(2)this關鍵字代表類的一個物件,所以其記憶體鎖是針對相同物件的互斥操作,而static成員屬於類專有,其記憶體空間為該類所有成員共有,這就導致synchronized()對static成員加鎖,相當於對類加鎖,也就是在該類的所有成員間實現互斥,在同一時間只有一個執行緒可訪問該類的例項。

二、Obj.wait()與Obj.notify()必須要與synchronized(Obj)一起使用,也就是wait與notify是針對已經獲取了Obj鎖的物件來進行操作。
(1)Obj.wait()、Obj.notify必須在synchronized(Obj){…}語句塊內。
(2)wait就是說執行緒在獲取物件鎖後,主動釋放物件鎖,同時本執行緒休眠。直到有其它執行緒呼叫物件的notify()喚醒該執行緒,才能繼續獲取物件鎖,並繼續執行。相應的notify()就是對物件鎖的喚醒操作。
(3)notify()呼叫後,並不是馬上就釋放物件鎖的,而是在相應的synchronized(){}語句塊執行結束,自動釋放鎖後,JVM會在wait()物件鎖的執行緒中隨機選取一執行緒,賦予其物件鎖,喚醒執行緒,繼續執行。如果是notifyAll()就會釋放所有的鎖。

注意:如果notify的物件沒有wait,會報IllegalMonitorStateException錯誤

這樣就提供了線上程間同步、喚醒的操作。Thread.sleep()與Object.wait()二者都可以暫停當前執行緒,釋放CPU控制權,主要的區別在於Object.wait()在釋放CPU同時,釋放了物件鎖的控制。

測試程式碼如下:

package com.demo.main;

public class WaitNotifyDemo {

    private static final Object syncObj = new Object();

    static
class WaitThread extends Thread { @Override public void run() { System.out.println("wait begin enter synchronized"); synchronized(syncObj) { try { System.out.println("wait start"); syncObj.wait(); System.out.println("wait end"); } catch (InterruptedException e) { e.printStackTrace(); } } } } static class NotifyThread extends Thread { @Override public void run() { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("notify begin enter synchronized"); synchronized(syncObj) { System.out.println("notify start"); syncObj.notifyAll(); System.out.println("notify end"); } } } static class SWaitThread extends Thread { @Override public void run() { System.out.println("Swait begin enter synchronized"); synchronized(syncObj) { try { System.out.println("Swait start"); //syncObj.wait(); Thread.sleep(3000); System.out.println("Swait end"); } catch (InterruptedException e) { e.printStackTrace(); } } } } static class SNotifyThread extends Thread { @Override public void run() { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Snotify begin enter synchronized"); synchronized(syncObj) { System.out.println("Snotify start"); // syncObj.notifyAll(); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Snotify end"); } } } public static void main(String[] args) { new WaitThread().start(); new NotifyThread().start(); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("============="); new SWaitThread().start(); new SNotifyThread().start(); try { Thread.sleep(6000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("============="); new WaitThread().start(); new WaitThread().start(); } }

執行截圖
這裡寫圖片描述