sleep、yield、wait、join的區別簡述

總體歸納:

1.  Thread.sleep(long) 和Thread.yield()都是Thread類的靜態方法,在調用的時候都是Thread.sleep(long)/Thread.yield()的方式進行調用。html

   而join()是由線程對象來調用。java

2.wait()和notify()、notifyAll()  這三個方法都是java.lang.Object的方法! 面試

Object 是java.lang.Object,由於每天說Java是面向對象的,因此Object是全部Java對象的超類,都實現Object的方法;dom

它們都是用於協調多個線程對共享數據的存取,因此必須在Synchronized語句塊內使用這三個方法。前面說過Synchronized這個關鍵字用於保護共享數據,阻止其餘線程對共享數據的存取。可是這樣程序的流程就很不靈活了,如何才能在當前線程還沒退出Synchronized數據塊時讓其餘線程也有機會訪問共享數據呢?此時就用這三個方法來靈活控制。 socket

wait()方法使當前線程暫停執行並釋放對象鎖標誌,讓其餘線程能夠進入Synchronized數據塊,當前線程被放入對象等待池中。ide

當調用 notify()方法後,將從對象的等待池中移走一個任意的線程並放到鎖標誌等待池中,只有鎖標誌等待池中的線程可以獲取鎖標誌;若是鎖標誌等待池中沒有線程,則notify()不起做用。 

notifyAll()則從對象等待池中移走全部等待那個對象的線程並放到鎖標誌等待池中。 this

sleep與Wait的區別:

看區別,主要是看CPU的運行機制:spa

它們的區別主要考慮兩點:1.cpu是否繼續執行、2.鎖是否釋放掉。線程

對於這兩點,首先解釋下cpu是否繼續執行的含義:cpu爲每一個線程劃分時間片去執行,每一個時間片時間都很短,cpu不停地切換不一樣的線程,以看似他們好像同時執行的效果。code

其次解釋下鎖是否釋放的含義:鎖若是被佔用,那麼這個執行代碼片斷是同步執行的,若是鎖釋放掉,就容許其它的線程繼續執行此代碼塊了。 

明白了以上兩點的含義,開始分析sleep和wait:

sleep一段時間以後,每每線程會當即執行,可見cpu一直在爲此線程分配時間片,若是外層包有Synchronize,那麼此鎖並無釋放掉。所以sleep cpu繼續執行、鎖並無釋放掉;

wait,通常用於鎖機制中

(wait用於鎖機制,sleep不是,這就是爲啥sleep不釋放鎖,wait釋放鎖的緣由,sleep是線程的方法,跟鎖沒半毛錢關係,wait,notify,notifyall是一塊兒使用的,用於鎖機制),

確定是要釋放掉鎖的,由於notify並不會當即調起此線程,所以cpu是不會爲其分配時間片的,也就是說wait 線程進入等待池,cpu不分時間片給它,鎖釋放掉。

說明:

1.sleep:Thread類的方法,必須帶一個時間參數。會讓當前線程休眠進入阻塞狀態並釋放CPU(阿里面試題 Sleep釋放CPU,wait呢),提供其餘線程運行的機會且不考慮優先級,但若是有同步鎖則sleep不會釋放鎖即其餘線程沒法得到同步鎖

2.yield:讓出CPU調度,Thread類的方法,相似sleep只是不能由用戶指定暫停多長時間 ,而且yield()方法只能讓同優先級的線程有執行的機會。 yield()只是使當前線程從新回到可執行狀態,因此執行yield()的線程有可能在進入到可執行狀態後立刻又被執行。調用yield方法只是一個建議,告訴線程調度器個人工做已經作的差很少了,可讓別的相同優先級的線程使用CPU了,沒有任何機制保證採納。

3.wait:Object類的方法(notify()、notifyAll()  也是Object對象),必須放在循環體和同步代碼塊中,執行該方法的線程會釋放鎖,進入線程等待池中等待被再次喚醒(notify隨機喚醒,notifyAll所有喚醒,線程結束自動喚醒)即放入鎖池中競爭同步鎖

4.join:一種特殊的wait,當前運行線程調用另外一個線程的join方法,當前線程進入阻塞狀態直到另外一個線程運行結束等待該線程終止。 注意該方法也須要捕捉異常。

等待調用join方法的線程結束,再繼續執行。如:t.join();//主要用於等待t線程運行結束,若無此句,main則會執行完畢,致使結果不可預測。

幾個方法的比較

  1. Thread.sleep(long millis),必定是當前線程調用此方法,當前線程進入阻塞,但不釋放對象鎖,millis後線程自動甦醒進入可運行狀態。做用:給其它線程執行機會的最佳方式。
  2. Thread.yield(),必定是當前線程調用此方法,當前線程放棄獲取的cpu時間片,由運行狀態變會可運行狀態,讓OS再次選擇線程。做用:讓相同優先級的線程輪流執行,但並不保證必定會輪流執行。實際中沒法保證yield()達到讓步目的,由於讓步的線程還有可能被線程調度程序再次選中。Thread.yield()不會致使阻塞。
  3. t.join()/t.join(long millis),當前線程裏調用其它線程1的join方法,當前線程阻塞,但不釋放對象鎖,直到線程1執行完畢或者millis時間到,當前線程進入可運行狀態。
  4. obj.wait(),當前線程調用對象的wait()方法,當前線程釋放對象鎖,進入等待隊列。依靠notify()/notifyAll()喚醒或者wait(long timeout)timeout時間到自動喚醒。
  5. obj.notify()喚醒在此對象監視器上等待的單個線程,選擇是任意性的。notifyAll()喚醒在此對象監視器上等待的全部線程。

show codes time

import lombok.extern.slf4j.Slf4j;

import java.util.Random;

/**
 * 實現線上
 * @author wucj
 * @date 2019-06-30 16:40
 **/
@Slf4j
public class ThreadAStatus implements Runnable{

    private String name;

    private volatile int count;

    public ThreadAStatus(String name){
        this.name = name;
    }

    @Override
    public void run() {
        log.info("線程{},執行次數:{}",name,++count);
        try{
            log.info("線程{}開始執行,當前第:{}次",name,count);
            int maxCount = 10;
            for(int i=0;i<maxCount;i++){
                log.info("線程{}開始執行,當前第:{}次",name,++count);
                int thisSleepSeconds = new Random().nextInt(5);
                log.info("線程:{},睡眠:{}秒",name,thisSleepSeconds);
            }
        }catch (Exception e){
            log.error("線程:{}異常:{}",name,e);
        }
    }
}


import com.cjw.concurrent.thd.ThreadAStatus;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

/**
 * @author wucj
 * @date 2019-06-30 16:47
 **/
@Slf4j
public class ThreadStatusTest {

    @Test
    public void threadStatusAB(){
        ThreadAStatus threadAStatus = new ThreadAStatus("A");
        ThreadAStatus threadBStatus = new ThreadAStatus("B");
        Thread threadA = new Thread(threadAStatus);
        Thread threadB = new Thread(threadBStatus);
        threadA.start();
        threadB.start();
        try{
            for(int i=0;i<10;i++){
                log.info("當前爲:{},執行第:{}次",Thread.currentThread().getName(),i);
                threadA.join();
                threadB.join();
            }
            Thread.sleep(100*1000);
        }catch (Exception e){
            log.error("thread.join異常{}",e);
        }

    }

}

Connected to the target VM, address: '127.0.0.1:64837', transport: 'socket'
17:25:06.227 [main] INFO com.cjw.concurrent.ThreadStatusTest - 當前爲:main,執行第:0次
17:25:06.227 [Thread-1] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程B,執行次數:1
17:25:06.227 [Thread-0] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程A,執行次數:1
17:25:06.248 [Thread-0] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程A開始執行,當前第:1次
17:25:06.247 [Thread-1] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程B開始執行,當前第:1次
17:25:06.248 [Thread-0] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程A開始執行,當前第:2次
17:25:06.248 [Thread-1] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程B開始執行,當前第:2次
17:25:06.251 [Thread-1] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程:B,睡眠:4秒
17:25:06.251 [Thread-0] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程:A,睡眠:3秒
17:25:06.251 [Thread-1] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程B開始執行,當前第:3次
17:25:06.251 [Thread-0] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程A開始執行,當前第:3次
17:25:06.251 [Thread-1] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程:B,睡眠:4秒
17:25:06.251 [Thread-0] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程:A,睡眠:2秒
17:25:06.251 [Thread-1] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程B開始執行,當前第:4次
17:25:06.251 [Thread-0] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程A開始執行,當前第:4次
17:25:06.251 [Thread-0] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程:A,睡眠:1秒
17:25:06.251 [Thread-1] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程:B,睡眠:2秒
17:25:06.251 [Thread-0] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程A開始執行,當前第:5次
17:25:06.251 [Thread-1] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程B開始執行,當前第:5次
17:25:06.251 [Thread-1] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程:B,睡眠:4秒
17:25:06.251 [Thread-1] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程B開始執行,當前第:6次
17:25:06.251 [Thread-1] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程:B,睡眠:4秒
17:25:06.251 [Thread-1] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程B開始執行,當前第:7次
17:25:06.251 [Thread-1] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程:B,睡眠:1秒
17:25:06.251 [Thread-1] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程B開始執行,當前第:8次
17:25:06.251 [Thread-1] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程:B,睡眠:3秒
17:25:06.251 [Thread-1] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程B開始執行,當前第:9次
17:25:06.252 [Thread-1] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程:B,睡眠:3秒
17:25:06.252 [Thread-1] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程B開始執行,當前第:10次
17:25:06.252 [Thread-1] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程:B,睡眠:2秒
17:25:06.252 [Thread-1] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程B開始執行,當前第:11次
17:25:06.252 [Thread-1] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程:B,睡眠:2秒
17:25:06.256 [Thread-0] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程:A,睡眠:3秒
17:25:06.256 [Thread-0] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程A開始執行,當前第:6次
17:25:06.256 [Thread-0] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程:A,睡眠:0秒
17:25:06.256 [Thread-0] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程A開始執行,當前第:7次
17:25:06.256 [Thread-0] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程:A,睡眠:1秒
17:25:06.257 [Thread-0] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程A開始執行,當前第:8次
17:25:06.257 [Thread-0] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程:A,睡眠:2秒
17:25:06.257 [Thread-0] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程A開始執行,當前第:9次
17:25:06.257 [Thread-0] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程:A,睡眠:1秒
17:25:06.257 [Thread-0] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程A開始執行,當前第:10次
17:25:06.257 [Thread-0] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程:A,睡眠:1秒
17:25:06.257 [Thread-0] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程A開始執行,當前第:11次
17:25:06.257 [Thread-0] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程:A,睡眠:1秒
17:25:06.257 [main] INFO com.cjw.concurrent.ThreadStatusTest - 當前爲:main,執行第:1次
17:25:06.257 [main] INFO com.cjw.concurrent.ThreadStatusTest - 當前爲:main,執行第:2次
17:25:06.257 [main] INFO com.cjw.concurrent.ThreadStatusTest - 當前爲:main,執行第:3次
17:25:06.257 [main] INFO com.cjw.concurrent.ThreadStatusTest - 當前爲:main,執行第:4次
17:25:06.257 [main] INFO com.cjw.concurrent.ThreadStatusTest - 當前爲:main,執行第:5次
17:25:06.257 [main] INFO com.cjw.concurrent.ThreadStatusTest - 當前爲:main,執行第:6次
17:25:06.257 [main] INFO com.cjw.concurrent.ThreadStatusTest - 當前爲:main,執行第:7次
17:25:06.257 [main] INFO com.cjw.concurrent.ThreadStatusTest - 當前爲:main,執行第:8次
17:25:06.257 [main] INFO com.cjw.concurrent.ThreadStatusTest - 當前爲:main,執行第:9次

參考地址:

http://www.javashuo.com/article/p-zrjvozwb-hp.html

http://www.javashuo.com/article/p-xvjmresi-bw.html

相關文章
相關標籤/搜索