java sleep join_Java多線程之sleep,wait,join和yield關鍵字

本文介绍了Java多线程中的wait、sleep、join和yield四个关键概念。wait和notify配合使用实现线程间的等待通知机制;sleep使线程暂停指定时间;join让调用线程等待目标线程执行完成后再继续;yield则让当前线程礼让,可能让其他线程优先执行。通过示例代码详细解释了这些方法的用法和效果。
摘要由CSDN通过智能技术生成

在java或者android中,使用Thread和Runnable就可以玩多線程了,這個成本比較低,也沒什么好說的,今天主要是針對多線程中主要的關鍵字wait,sleep,join和yield做個筆記,加強一下印象。

wait

wait方法一般都是和notity()或者notifyAll()成對出現的。當某個線程執行到wait()方法時,它就進入到一個和該對象相關的等待池中,同時失去了對象的鎖功能,使得其他線程可以訪問該對象。用戶可以使用notify或者notifyAll或者指定睡眠時間來喚醒當前等待池中的線程。wait,notify和notifyAll方法都必須放在synchronized 代碼塊中,否則就會報java.lang.IllegalMonitorStateException。

下面的例子中,在主線程中會存在一個waitObject對象使用wait方法進行等待,而開啟子線程睡眠3秒之后,notifyAll該waitObject對象,使得主線程繼續執行:private static Object waitObject = new Object();

public static void main(String[] args) {

System.out.println("主線程開始運行");

WaitThread thread = new WaitThread();

thread.start();

long t1 = System.currentTimeMillis();

try{

synchronized(waitObject) {

System.out.println("主線程等待");

waitObject.wait();

System.out.println("主線程等待結束");

}

}catch(Exception e){

e.printStackTrace();

}

long t2 = System.currentTimeMillis();

System.out.println("最終時間為:" + (t2 - t1));

}

//定義等待線程

static class WaitThread extends Thread{

@Override

public void run() {

System.out.println("進入子線程run方法");

try{

sleep(3000);

synchronized(waitObject) {

waitObject.notifyAll();

System.out.println("子線程notifyAll結束");

}

}catch(Exception e) {

e.printStackTrace();

}

}

}

程序運行的結果為:

8efee7f8559c736c510b14f38352eb2b.png

可見wait和notity可用於等待機制的實現,當條件不滿足時進行等待,一旦條件滿足,則notity或者notifyAll喚醒等待線程繼續執行。經典的消費者-生產者模式可以使用wait和notity進行設計。

join

等待目標線程執行完成之后再繼續執行。說的比較含糊,還是來看看例子吧。下面有兩個工作子線程,都需要進行2s的耗時才能完成任務:public static void main(String[] args) throws Exception {

Thread t1 = new WorkThread("work1");

Thread t2 = new WorkThread("work2");

t1.start();

//t1.join();

t2.start();

//t2.join();

System.out.println("當前主線程結束");

}

//工作線程

static class WorkThread extends Thread{

public WorkThread(String name){

super(name);

}

@Override

public void run() {

try {

sleep(2000);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("the current thread is " + getName());

}

}

首先先注釋掉join方法,直接運行,可以看到的結果如下圖:

79f160de18a95168353eec67be0673aa.png

我們可以看到,主線程首先執行完成,而后兩個子線程分別執行完成,現在我們打開我們的t1.join()和t2.join()方法,得出的結果為:

a1761a301df336cb06c75099f093163d.png

程序執行的順序是 t1->t2->main thread,相當於三個程序的串聯執行,這也就是join的作用,一旦某個線程使用了join,那么它就先執行完畢,其他線程才有機會繼續執行。

yield

線程禮讓。使用yield方法的線程將由運行狀態轉變為就緒狀態,也就是讓出執行的狀態,讓其他線程得以優先執行,但是其他線程未必一定是有限執行的。簡單通俗一點,就是線程先等着,我會讓其他線程有優先的機會去運行。下面的例子可以簡單說明問題:有兩個單獨的子線程t1,t2分別獨自運行,t1中run遍歷到4時,會執行yield方法,那么我們的猜測就是此時t1將會變回就緒狀態,不再搶奪CPU資源,等到其他線程執行完畢后,再次從就緒狀態變為運行狀態,從而完成以后的任務。代碼如下:public static void main(String[] args) {

//線程t1運行到4時 會執行yield方法

Thread t1 = new YieldClass("線程1",4);

//線程t2將一直運行下去

Thread t2 = new YieldClass("線程2",-1);

t1.start();

t2.start();

System.out.println("主線程結束");

}

static class YieldClass extends Thread{

public int mIndex ;

public YieldClass(String name ,int index) {

super(name);

this.mIndex = index;

}

@Override

public void run() {

for(int i = 0 ; i < 10 ; i++) {

System.out.println(Thread.currentThread().getName() + "---" + i);

if(i == mIndex) {

yield();

}

}

}

}

我們來看運行的效果圖:

8c14de1cafab2fa05c2f80d7831dd70d.png

可以看到圖中,t1和t2先並行運行,可是當t1運行到4時,由於執行了yield方法,此時t1將會變為就緒狀態,t2線程會執行下去,t2線程執行完成之后,t1才會繼續執行,跟我們預想的方式是一樣的。

sleep

sleep方法是我們平常用得最多的,它是Thread的靜態函數,作用是使得調用的Thread進入休眠狀態。由於是Static修飾的方法,因此不能修改對象的鎖機制,所以當一個synchronized塊中調用了sleep方法,線程雖然休眠了,但是對象的鎖機制並沒有被釋放。其他線程將會無法訪問到這個對象。下面舉個例子:有兩個子線程,一個需要睡眠3s,另一個不需要睡眠,兩個子線程都使用了synchronized塊,我們來看看兩個線程結束之后所用的時間,代碼如下:public class TestSleep {

private static Object mLock = new Object();

public static void main(String[] args) {

Thread t1 = new SleepThread();

Thread t2 = new WordThread() ;

t1.start();

t2.start();

System.out.println("-----主線程執行完成-----"+ System.currentTimeMillis());

}

static class SleepThread extends Thread {

@Override

public void run() {

synchronized(mLock){

try {

sleep(3000);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("----睡眠線程執行完成-----" + System.currentTimeMillis());

}

}

}

static class WordThread extends Thread{

@Override

public void run() {

synchronized (mLock) {

System.out.println("----工作線程執行完成-----" + System.currentTimeMillis());

}

}

}

}

結果為:

2544f8a3536a8df7c5e691cd5eba6a34.png

我們發現了睡眠線程和工作線程幾乎都是等待了3秒之后才結束的,這就表明了sleep引用了對象鎖,其他線程將無法訪問該對象了。我們去掉synchronized代碼塊,再來看一次結果:

f45e96129f55bfc03cb16b3305b864f6.png

我們發現睡眠線程和主線程幾乎同時完成工作,只有睡眠線程睡眠3秒之后才結束工作,由於沒有引用相同的對象,線程之間不影響各自的工作,此時就不存在同步的問題了。

好了,今天基本上就說到這里了,由於以前很少了解這些東西,以致很多關於多線程方面的東西都看得不是很懂,今天算是個入門吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值