java多線程知識點之wait和sleep的區別
Sleep vs Wait
java虛擬機支持多線程開發。在多線程開發中我們可以用線程來啓動、執行、結束某些程序控制。在多線程同步開發中我們會接觸到兩個不同的方法——wait 和 sleep
wait和sleep都是用來控制線程的執行與等待方法。sleep方法是讓當前線程延遲一段時間再執行下一句程序指令,wait不會直接讓當前線程延遲控制指令執行,而是讓線程暫時掛起狀態。
一、wait方法:
wait是屬於object類的方法,在java中所有類都是繼承於object類,當調用wait方法時會將調用方法所處的線程切換到掛起不執行狀態。與wait相對應的有notify和notifyAll方法可以讓處於wait的object的線程恢復到運行狀態。
wait方法必須在synchronized同步所內部調用。當object被調用的時候,java虛擬機(後續稱爲系統)釋放object所對應的synchronized的lock鎖,然後再把調用wait的當前線程掛起並添加到wait列表,系統在wait的時候釋放lock鎖是爲了讓其他線程能能夠synchronized加鎖以便於用notify或者notifyAll喚醒wait列表中相應object的線程。
二、sleep方法:
sleep屬於Thread線程類的一個靜態方法。調用該方法會是當前線程延遲一段時間後執行下一句控制指令,在延遲這段時間內當前線程並沒有任何object對象被標記掛起或者其他操作。對於synchronized內的sleep方法,在sleep期間其他線程不能夠進入相同synchronized對象內部。
三、小節
1. sleep是線程thread類的靜態方法,wait是一個實例化對象的線程控制方法;
2. sleep是thread線程類操作內的方法,wait是任意對象內的方法,範圍不同;
3. sleep方法會保留synchronized內的lock鎖,wait不會保存synchronized內的鎖;
4. 對於synchonized內部執行wait在不執行線程期間不會影響其他線程進入相同的synchronized同步塊,而sleep則不允許在sleep期間其他線程進入synchronized內。
=============================================================
# 以上內容來自文章:
http://www.differencebetween.net/technology/software-technology/difference-between-sleep-and-wait/
的部分翻譯
=============================================================
在多線程同於應用上的最大區別就是wait可以釋放synchronized中的鎖,而sleep不會釋放。
接下來我們用demo來演示一下這個特性
一、SleepDemo
SleepDemo通過兩個線程,SleepThread線程會在synchronized執行中sleep 3秒鐘,ReadThread線程直接運行,但是會在運行中經過synchronized代碼塊。由於Thread.sleep在延遲執行時不會釋放synchronized持有的鎖,所以ReadThread必須等待SleepThread退出鎖後繼續運行,具體代碼如下
import java.lang.Thread;
public class SleepDemo {
public static void main(String args[]) {
Object lock = new Object();
SleepThread t1 = new SleepThread(lock);
t1.start();
// sleep to ensure thread of t1 start before t2
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
ReadThread t2 = new ReadThread(lock);
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class SleepThread extends Thread {
Object lock = new Object();
public SleepThread(Object lock) {
this.lock = lock;
}
@Override
public void run() {
System.out.println("SleepThread before synchronized");
synchronized (lock) {
System.out.println("SleepThread enter synchronized");
System.out.println("SleepThread before sleep");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("SleepThread after sleep");
System.out.println("SleepThread exit synchronized");
}
System.out.println("SleepThread after synchronized");
}
}
class ReadThread extends Thread {
Object lock = new Object();
public ReadThread(Object lock) {
this.lock = lock;
}
@Override
public void run() {
System.out.println("ReadThread before synchronized");
synchronized (lock) {
System.out.println("ReadThread enter synchronized");
System.out.println("ReadThread exit synchronized");
}
System.out.println("ReadThread after synchronized");
}
}
編譯:
$ javac SleepDemo.java
$ java SleepDemo
SleepThread before synchronized
SleepThread enter synchronized
SleepThread before sleep
ReadThread before synchronized
SleepThread after sleep
SleepThread exit synchronized
SleepThread after synchronized
ReadThread enter synchronized
ReadThread exit synchronized
ReadThread after synchronized
ReadThread準備進入synchronized塊時由於鎖被SleepThread的synchronized持有,必須等待sleep結束後退出synchronized塊才能往下繼續執行。
二、WaitDemo
SleepDemo通過兩個線程,WaitThread線程會在synchronized執行中sleep 3秒鐘,ReadThread線程直接運行,但是會在運行中經過synchronized代碼塊。由於Object.wait在被掛起時釋放synchronized持有的鎖,ReadThread執行synchronized代碼時如果WaitThead已經處於wait狀態時能夠繼續進入synchronized代碼,不需要等待,具體代碼如下
import java.lang.Thread;
public class WaitDemo {
public static void main(String args[]) {
Object lock = new Object();
WaitThread t1 = new WaitThread(lock);
t1.start();
// sleep to ensure thread of t1 start before t2
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
ReadThread t2 = new ReadThread(lock);
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class WaitThread extends Thread {
Object lock = new Object();
public WaitThread(Object lock) {
this.lock = lock;
}
@Override
public void run() {
System.out.println("WaitThread before synchronized");
synchronized (lock) {
System.out.println("WaitThread enter synchronized");
System.out.println("WaitThread before wait");
try {
lock.wait(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("WaitThread after wait");
System.out.println("WaitThread exit synchronized");
}
System.out.println("WaitThread after synchronized");
}
}
class ReadThread extends Thread {
Object lock = new Object();
public ReadThread(Object lock) {
this.lock = lock;
}
@Override
public void run() {
System.out.println("ReadThread before synchronized");
synchronized (lock) {
System.out.println("ReadThread enter synchronized");
System.out.println("ReadThread exit synchronized");
}
System.out.println("ReadThread after synchronized");
}
}
編譯運行
$ javac WaitDemo.java
$ java WaitDemo
WaitThread before synchronized
WaitThread enter synchronized
WaitThread before wait
ReadThread before synchronized
ReadThread enter synchronized
ReadThread exit synchronized
ReadThread after synchronized
WaitThread after wait
WaitThread exit synchronized
WaitThread after synchronized
可以看看到synchronized調用wait後不會影響其他synchronized鎖的代碼。