0.sleep和wait的區別
sleep()
是使線程暫停執行一段時間的方法。wait()
也是一種使線程暫停執行的方法。例如,當線程執行wait()
方法時候,會釋放當前的鎖,然後讓出CPU的執行權,進入等待狀態。並且可以調用notify()
方法或者notifyAll()
方法通知正在等待的其他線程。notify()
方法僅喚醒一個線程(等待隊列中的第一個線程)並允許他去獲得鎖。notifyAll()
方法喚醒所有等待這個對象的線程並允許他們去競爭獲得鎖。具體區別如下:
1.原理不同。sleep()
方法是Thread
類的靜態方法,是線程用來控制自身流程的,他會使此線程暫停執行一段時間,而把執行機會讓給其他線程,等到計時時間一到,此線程會自動甦醒。例如,當線程執行報時功能時,每一秒鐘打印出一個時間,那麼此時就需要在打印方法前面加一個sleep()
方法,以便讓自己每隔一秒執行一次,該過程如同鬧鐘一樣。而wait()
方法是Object
類的方法,用於線程間通信,這個方法會使當前擁有該對象鎖的進程等待,直到其他線程調用notify()
方法或者notifyAll()
時才醒來,不過開發人員也可以給他指定一個時間,自動醒來。
2.對鎖的 處理機制不同。由於sleep()
方法的主要作用是讓線程暫停執行一段時間,時間一到則自動恢復,不涉及線程間的通信,因此,調用sleep()
方法並不會釋放鎖。而wait()
方法則不同,當調用wait()
方法後,線程會釋放掉他所佔用的鎖,從而使線程所在對象中的其他synchronized
數據可以被其他線程使用。
3.使用區域不同。wait()
方法必須放在同步控制方法和同步代碼塊中使用,sleep()
方法則可以放在任何地方使用。sleep()
方法必須捕獲異常,而wait()
、notify()
、notifyAll()
不需要捕獲異常。在sleep
的過程中,有可能被其他對象調用他的interrupt()
,產生InterruptedException
。由於sleep
不會釋放鎖標誌,容易導致死鎖問題的發生,因此一般情況下,推薦使用wait()
方法。
1.wait方法
wait方法是Object
提供方法,可通過wait
方法讓當前線程進入等待。
1.1 先看看wait方法的介紹。
通過查閱JDK1.8文檔發現Object
中的wait
方法有三個重載方法。
分別爲:
- void wait()
導致當前線程等待,直到另一個線程爲此對象調用notify()
方法或notifyAll()
方法。實際上wait()
方法是僅僅是調用wait(0L)
。
- void wait(long timeout)
導致當前線程等待,直到另一個線程調用此對象的notify()
方法或notifyAll()
方法,或者已經過了指定的時間量,如果timeout爲0L那麼將爲永久等待相當於調用wait()
。
- void wait(long timeout, int nanos)
導致當前線程等待,直到另一個線程爲此對象調用notify()
方法或notifyAll()
方法,或者某個其他線程中斷當前線程,或者已經過了一定量的實時。
1.2 wait方法的特點
1.wait方法只能在synchronized
代碼塊內調用,否則會拋出IllegalMonitorStateException
異常。也就是說調用wait
方法的線程必須持有鎖。
示例代碼
package spring.cache.jvm;
public class Demo implements Runnable{
@Override
public void run() {
System.out.println("start");
long start = System.currentTimeMillis();
try {
this.wait(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("end");
System.out.println(end-start);
}
public static void main(String[] args) {
Demo demo = new Demo();
Thread thread1 = new Thread(demo);
thread1.start();
}
}
控制檯
start
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at spring.cache.jvm.Demo.run(Demo.java:25)
at java.lang.Thread.run(Thread.java:748)
進程完成,退出碼 0
2.線程調用wait
方法時該線程釋放此鎖(監視器)的所有權並進入等待狀態,並把CPU的執行權讓給其他線程,直到其他線程調用notify
方法或notifyAll
方法喚醒。
public class Demo implements Runnable{
@Override
public void run() {
System.out.println("start");
synchronized (this){
try {
System.out.println("當前線程名字爲:"
+Thread.currentThread().getName());
//喚醒其它正在等待的線程
this.notify();
//導致線程等待,並釋放鎖。
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("end");
}
public static void main(String[] args) {
Demo demo = new Demo();
Thread thread1 = new Thread(demo);
thread1.start();
Thread thread2 = new Thread(demo);
thread2.start();
}
}
控制檯
start
start
當前線程名字爲:Thread-0
當前線程名字爲:Thread-1
end
1.3 wait方法實現
1.wait()
源碼
public final void wait() throws InterruptedException {
this.wait(0L);
}
wait()
方法其實是調用wait(long timeout)
方法並傳入參數0L
2.wait(long timeout)
源碼
public final native void wait(long timeout) throws InterruptedException;
wait(long timeout)
方法被native
修飾了,也就是說他不是java方法,他是一個本地方法,底層實現的可能是C和C++。
3.wait(long timeout, int nanos)
源碼
public final void wait(long timeout, int nanos) throws InterruptedException {
if (timeout < 0L) {//timeout小於0則報錯
throw new IllegalArgumentException("timeout value is negative");
} else if (nanos >= 0 && nanos <= 999999) {//nanos 大於等於 0 && 小於等於 999999
if (nanos > 0) { //nanos 大於 0
++timeout; //timeout自增1
}
this.wait(timeout); //調用wait(long timeout)
} else {
throw new IllegalArgumentException("nanosecond timeout value out of range");
}
}
wait(long timeout, int nanos)
文檔中的介紹解釋的不是很清楚,通過翻閱源碼發現其實wait(long timeout, int nanos)
底層也是調用wait(long timeout)
方法,只不過做了些處理,如果nanos
有值的話,並且nanos
大於0,則timeout
加1。舉個例子:例如this.wait(1000,999)
那麼這時候線程實際等待時間爲1001
。
2.sleep方法
sleep
是Thread
對象提供的方法,可通過sleep
方法讓當前線程進入休眠。
2.1 先看看sleep方法的介紹。
通過查閱JDK1.8文檔發現Thread
中的sleep
方法有兩個重載方法。
- static void sleep(long timeout)
使當前正在執行的線程以指定的毫秒數暫停(暫時停止執行),具體取決於系統定時器和調度程序的精度和準確性。
- static void sleep(long timeout, int nanos)
導致正在執行的線程以指定的毫秒數加上指定的納秒數來暫停(臨時停止執行),這取決於系統定時器和調度器的精度和準確性。
2.2 sleep方法的特點
1.sleep可以在synchronized
代碼塊內調用,也就是說調用sleep
的線程不用持有鎖。
示例代碼
package spring.cache.jvm;
public class Demo implements Runnable{
@Override
public void run() {
long start = System.currentTimeMillis();
try {
//讓線程休眠1秒
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("執行時間:"+(end-start));
}
public static void main(String[] args) {
Demo demo = new Demo();
Thread thread = new Thread(demo);
thread.start();
}
}
控制檯
執行時間:1000
進程完成,退出碼 0
2.sleep
方法讓線程休眠並不會釋放鎖,但會交出CPU的執行權。
示例代碼
package spring.cache.jvm;
public class Demo implements Runnable{
@Override
public void run() {
long start = System.currentTimeMillis();
synchronized (this){
try {
//讓線程休眠1秒
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
long end = System.currentTimeMillis();
System.out.println(Thread.currentThread().getName()+"的執行時間:"
+(end-start));
}
public static void main(String[] args) {
Demo demo = new Demo();
Thread thread = new Thread(demo);
thread.start();
Thread thread1 = new Thread(demo);
thread1.start();
}
}
控制檯
Thread-0的執行時間:1000
Thread-1的執行時間:2000
進程完成,退出碼 0
1.線程Thread-0
進入synchronized
代碼塊,得到同步鎖並進入休眠1秒,Thread-1
嘗試獲取鎖,獲取不到(鎖此時被Thread-0
佔用)。
2.Thread-0
喚醒出synchronized
代碼塊釋放鎖並打印,Thread-1
獲取到鎖進行等待1秒後打印。
2.sleep方法讓線程休眠並不會釋放鎖,但會交出CPU的執行權。
2.3 sleep方法實現
1.sleep(long timeout)
源碼
public static native void sleep(long timeout) throws InterruptedException;
sleep(long timeout)
方法被native
修飾了,也就是說他不是java方法,他是一個本地方法,底層實現的可能是C和C++。
2.sleep(long timeout, int nanos)
源碼
public static void sleep(long timeout, int nanos) throws InterruptedException {
if (timeout< 0L) { //過期時間小於0L 拋出 超時值爲負 異常。
throw new IllegalArgumentException("timeout value is negative");
} else if (nanos>= 0 && nanos<= 999999) {//nanos 大於等於 0 && 小於等於 999999
if (nanos >= 500000 || (nanos!= 0 && timeout== 0L)) { // nanos 大於等於 500000 或者nanos 不等於 0 並且 timeout 等等於 0L
++timeout; //timeout自增
}
sleep(timeout);
} else {
throw new IllegalArgumentException("nanosecond timeout value out of range");
}
}
sleep(long timeout, int nanos)
文檔中的介紹解釋的不是很清楚,通過翻閱源碼發現其實sleep(long timeout, int nanos)
底層也是調用sleep(long timeout)
方法,只不過做了些處理,具體看上面源碼解讀。
3.sleep和wait方法區別總結
wait
由Object
提供,sleep
由Thread
提供。wait
方法只能在synchronized
代碼塊內調用,而sleep
沒有做限制。wait
方法讓線程陷入等待/休眠階段時,會釋放同步鎖。而sleep
並不會釋放同步鎖。wait
方法可以不指定時間戳(線程的休眠時間)將由notify()
方法或notifyAll()
方法喚醒。而sleep
必需指定時間戳(線程的休眠時間)。
以上就是wait
和sleep
的一個區別,有一篇文章講的還是蠻不錯的。如果大家看完還是不能夠很好總結可以參考一下這篇文章:
https://blog.csdn.net/qiuchaoxi/article/details/79837568