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();
}
}
執行截圖