溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

java中sleep、yield、wait、join的區(qū)別是什么

發(fā)布時間:2021-07-06 11:57:35 來源:億速云 閱讀:250 作者:chen 欄目:大數(shù)據(jù)

這篇文章主要講解了“java中sleep、yield、wait、join的區(qū)別是什么”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“java中sleep、yield、wait、join的區(qū)別是什么”吧!

整體概括:

1.  Thread.sleep(long) 和Thread.yield()都是Thread類的靜態(tài)方法,在調(diào)用的時候都是Thread.sleep(long)/Thread.yield()的方式進(jìn)行調(diào)用。

   而join()是由線程對象來調(diào)用。

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

Object 是java.lang.Object,因為天天說Java是面向?qū)ο蟮?/strong>,所以O(shè)bject是所有Java對象的超類,都實(shí)現(xiàn)Object的方法;

它們都是用于協(xié)調(diào)多個線程對共享數(shù)據(jù)的存取,所以必須在Synchronized語句塊內(nèi)使用這三個方法。前面說過Synchronized這個關(guān)鍵字用于保護(hù)共享數(shù)據(jù),阻止其他線程對共享數(shù)據(jù)的存取。但是這樣程序的流程就很不靈活了,如何才能在當(dāng)前線程還沒退出Synchronized數(shù)據(jù)塊時讓其他線程也有機(jī)會訪問共享數(shù)據(jù)呢?此時就用這三個方法來靈活控制。 

wait()方法使當(dāng)前線程暫停執(zhí)行并釋放對象鎖標(biāo)志,讓其他線程可以進(jìn)入Synchronized數(shù)據(jù)塊,當(dāng)前線程被放入對象等待池中。

當(dāng)調(diào)用 notify()方法后,將從對象的等待池中移走一個任意的線程并放到鎖標(biāo)志等待池中,只有鎖標(biāo)志等待池中的線程能夠獲取鎖標(biāo)志;如果鎖標(biāo)志等待池中沒有線程,則notify()不起作用。 

notifyAll()則從對象等待池中移走所有等待那個對象的線程并放到鎖標(biāo)志等待池中。 

sleep與Wait的區(qū)別:

看區(qū)別,主要是看CPU的運(yùn)行機(jī)制:

它們的區(qū)別主要考慮兩點(diǎn):1.cpu是否繼續(xù)執(zhí)行、2.鎖是否釋放掉。

對于這兩點(diǎn),首先解釋下cpu是否繼續(xù)執(zhí)行的含義:cpu為每個線程劃分時間片去執(zhí)行,每個時間片時間都很短,cpu不停地切換不同的線程,以看似他們好像同時執(zhí)行的效果。

其次解釋下鎖是否釋放的含義:鎖如果被占用,那么這個執(zhí)行代碼片段是同步執(zhí)行的,如果鎖釋放掉,就允許其它的線程繼續(xù)執(zhí)行此代碼塊了。 

明白了以上兩點(diǎn)的含義,開始分析sleep和wait:

sleep一段時間之后,往往線程會立即執(zhí)行,可見cpu一直在為此線程分配時間片,如果外層包有Synchronize,那么此鎖并沒有釋放掉。因此sleep cpu繼續(xù)執(zhí)行、鎖并沒有釋放掉;

wait,一般用于鎖機(jī)制中

(wait用于鎖機(jī)制,sleep不是,這就是為啥sleep不釋放鎖,wait釋放鎖的原因,sleep是線程的方法,跟鎖沒半毛錢關(guān)系,wait,notify,notifyall是一起使用的,用于鎖機(jī)制),

肯定是要釋放掉鎖的,因為notify并不會立即調(diào)起此線程,因此cpu是不會為其分配時間片的,也就是說wait 線程進(jìn)入等待池,cpu不分時間片給它,鎖釋放掉。

說明:

1.sleep:Thread類的方法,必須帶一個時間參數(shù)。會讓當(dāng)前線程休眠進(jìn)入阻塞狀態(tài)并釋放CPU(阿里面試題 Sleep釋放CPU,wait呢),提供其他線程運(yùn)行的機(jī)會且不考慮優(yōu)先級,但如果有同步鎖則sleep不會釋放鎖即其他線程無法獲得同步鎖

2.yield:讓出CPU調(diào)度,Thread類的方法,類似sleep只是不能由用戶指定暫停多長時間 ,并且yield()方法只能讓同優(yōu)先級的線程有執(zhí)行的機(jī)會。 yield()只是使當(dāng)前線程重新回到可執(zhí)行狀態(tài),所以執(zhí)行yield()的線程有可能在進(jìn)入到可執(zhí)行狀態(tài)后馬上又被執(zhí)行。調(diào)用yield方法只是一個建議,告訴線程調(diào)度器我的工作已經(jīng)做的差不多了,可以讓別的相同優(yōu)先級的線程使用CPU了,沒有任何機(jī)制保證采納。

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

4.join:一種特殊的wait,當(dāng)前運(yùn)行線程調(diào)用另一個線程的join方法,當(dāng)前線程進(jìn)入阻塞狀態(tài)直到另一個線程運(yùn)行結(jié)束等待該線程終止。 注意該方法也需要捕捉異常。

等待調(diào)用join方法的線程結(jié)束,再繼續(xù)執(zhí)行。如:t.join();//主要用于等待t線程運(yùn)行結(jié)束,若無此句,main則會執(zhí)行完畢,導(dǎo)致結(jié)果不可預(yù)測。

幾個方法的比較

  1. Thread.sleep(long millis),一定是當(dāng)前線程調(diào)用此方法,當(dāng)前線程進(jìn)入阻塞,但不釋放對象鎖,millis后線程自動蘇醒進(jìn)入可運(yùn)行狀態(tài)。作用:給其它線程執(zhí)行機(jī)會的最佳方式。

  2. Thread.yield(),一定是當(dāng)前線程調(diào)用此方法,當(dāng)前線程放棄獲取的cpu時間片,由運(yùn)行狀態(tài)變會可運(yùn)行狀態(tài),讓OS再次選擇線程。作用:讓相同優(yōu)先級的線程輪流執(zhí)行,但并不保證一定會輪流執(zhí)行。實(shí)際中無法保證yield()達(dá)到讓步目的,因為讓步的線程還有可能被線程調(diào)度程序再次選中。Thread.yield()不會導(dǎo)致阻塞。

  3. t.join()/t.join(long millis),當(dāng)前線程里調(diào)用其它線程1的join方法,當(dāng)前線程阻塞,但不釋放對象鎖,直到線程1執(zhí)行完畢或者millis時間到,當(dāng)前線程進(jìn)入可運(yùn)行狀態(tài)。

  4. obj.wait(),當(dāng)前線程調(diào)用對象的wait()方法,當(dāng)前線程釋放對象鎖,進(jìn)入等待隊列。依靠notify()/notifyAll()喚醒或者wait(long timeout)timeout時間到自動喚醒。

  5. obj.notify()喚醒在此對象監(jiān)視器上等待的單個線程,選擇是任意性的。notifyAll()喚醒在此對象監(jiān)視器上等待的所有線程。

show codes time

import lombok.extern.slf4j.Slf4j;

import java.util.Random;

/**
 * 實(shí)現(xiàn)線上
 * @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("線程{},執(zhí)行次數(shù):{}",name,++count);
        try{
            log.info("線程{}開始執(zhí)行,當(dāng)前第:{}次",name,count);
            int maxCount = 10;
            for(int i=0;i<maxCount;i++){
                log.info("線程{}開始執(zhí)行,當(dāng)前第:{}次",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("當(dāng)前為:{},執(zhí)行第:{}次",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 - 當(dāng)前為:main,執(zhí)行第:0次
17:25:06.227 [Thread-1] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程B,執(zhí)行次數(shù):1
17:25:06.227 [Thread-0] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程A,執(zhí)行次數(shù):1
17:25:06.248 [Thread-0] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程A開始執(zhí)行,當(dāng)前第:1次
17:25:06.247 [Thread-1] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程B開始執(zhí)行,當(dāng)前第:1次
17:25:06.248 [Thread-0] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程A開始執(zhí)行,當(dāng)前第:2次
17:25:06.248 [Thread-1] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程B開始執(zhí)行,當(dāng)前第: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開始執(zhí)行,當(dāng)前第:3次
17:25:06.251 [Thread-0] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程A開始執(zhí)行,當(dāng)前第: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開始執(zhí)行,當(dāng)前第:4次
17:25:06.251 [Thread-0] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程A開始執(zhí)行,當(dāng)前第: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開始執(zhí)行,當(dāng)前第:5次
17:25:06.251 [Thread-1] INFO com.cjw.concurrent.thd.ThreadAStatus - 線程B開始執(zhí)行,當(dāng)前第: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開始執(zhí)行,當(dāng)前第: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開始執(zhí)行,當(dāng)前第: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開始執(zhí)行,當(dāng)前第: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開始執(zhí)行,當(dāng)前第: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開始執(zhí)行,當(dāng)前第: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開始執(zhí)行,當(dāng)前第: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開始執(zhí)行,當(dāng)前第: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開始執(zhí)行,當(dāng)前第: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開始執(zhí)行,當(dāng)前第: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開始執(zhí)行,當(dāng)前第: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開始執(zhí)行,當(dāng)前第: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開始執(zhí)行,當(dāng)前第: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 - 當(dāng)前為:main,執(zhí)行第:1次
17:25:06.257 [main] INFO com.cjw.concurrent.ThreadStatusTest - 當(dāng)前為:main,執(zhí)行第:2次
17:25:06.257 [main] INFO com.cjw.concurrent.ThreadStatusTest - 當(dāng)前為:main,執(zhí)行第:3次
17:25:06.257 [main] INFO com.cjw.concurrent.ThreadStatusTest - 當(dāng)前為:main,執(zhí)行第:4次
17:25:06.257 [main] INFO com.cjw.concurrent.ThreadStatusTest - 當(dāng)前為:main,執(zhí)行第:5次
17:25:06.257 [main] INFO com.cjw.concurrent.ThreadStatusTest - 當(dāng)前為:main,執(zhí)行第:6次
17:25:06.257 [main] INFO com.cjw.concurrent.ThreadStatusTest - 當(dāng)前為:main,執(zhí)行第:7次
17:25:06.257 [main] INFO com.cjw.concurrent.ThreadStatusTest - 當(dāng)前為:main,執(zhí)行第:8次
17:25:06.257 [main] INFO com.cjw.concurrent.ThreadStatusTest - 當(dāng)前為:main,執(zhí)行第:9次

參考地址:

https://www.cnblogs.com/aspirant/p/8900276.html

https://www.cnblogs.com/aspirant/p/8876670.html

感謝各位的閱讀,以上就是“java中sleep、yield、wait、join的區(qū)別是什么”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對java中sleep、yield、wait、join的區(qū)別是什么這一問題有了更深刻的體會,具體使用情況還需要大家實(shí)踐驗證。這里是億速云,小編將為大家推送更多相關(guān)知識點(diǎn)的文章,歡迎關(guān)注!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI