日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Thread源码分析之join方法

發布時間:2024/9/21 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Thread源码分析之join方法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

2019獨角獸企業重金招聘Python工程師標準>>>

join方法示例1

源碼

import java.util.concurrent.TimeUnit;public class JoinWaitTest {private static int a = 0;private static int b = 100;public static void main(String... args) throws InterruptedException{Thread t = new Thread(new WaitThread());t.start();t.join();System.out.println("I'm waiting for WaitThread end.");System.out.println("The result is " + (a + b));}static class WaitThread implements Runnable {@Overridepublic void run() {try {for (int i = 1; i < 6; i++) {TimeUnit.SECONDS.sleep(1);a++;System.out.println(i);}} catch (InterruptedException e) {}}} }

執行結果

1

2

3

4

5

I'm waiting for WaitThread end.

The result is 105

場景描述

在很多情況下,主線程生成并啟動了子線程,如果子線程里要進行大量的耗時的運算,主線程往往將于子線程之前結束,但是如果主線程處理完其他的事務后,需要用到子線程的處理結果,也就是主線程需要等待子線程執行完成之后再結束,這個時候就要用到join()方法了。

本例只是個示例,演示的就是上述的過程。

join方法示例2

源碼

import java.util.concurrent.TimeUnit;public class JoinTest {public static void main(String... args) throws InterruptedException {Thread jt = new Thread(new JoinThread());Thread tt = new Thread(new TimingThread());tt.start();tt.join();jt.start();}static class JoinThread implements Runnable {@Overridepublic void run() {System.out.println("I have waited for too long.");}}static class TimingThread implements Runnable {@Overridepublic void run() {for (int i = 0; i < 6; i++) {try {TimeUnit.SECONDS.sleep(1);System.out.println("Sleep end!");} catch (InterruptedException e) {}}}} }

執行結果

Sleep end!

Sleep end!

Sleep end!

Sleep end!

Sleep end!

Sleep end!

I have waited for too long.

場景描述

跟源碼示例1大同小異,只不過這次是jt線程要等待tt線程結束。

join不帶參數源碼分析2--必須在同步方法/同步代碼塊中調用wait方法------為什么wait()【還有notify(),notifyAll()】必須在同步方法/代碼塊中調用

????在 Java中,所有對象都能夠被作為"監視器monitor"——指一個擁有一個獨占鎖,一個入口隊列和一個等待隊列的實體entity。

  所有對象的非同步方法都能夠在任意時刻被任意線程調用,此時不需要考慮加鎖的問題。

  而對于對象的同步方法來說,在任意時刻有且僅有一個擁有該對象獨占鎖的線程能夠調用它們。例如,一個同步方法是獨占的。如果在線程調用某一對象的同步方法時,對象的獨占鎖被其他線程擁有,那么當前線程將處于阻塞狀態,并添加到對象的入口隊列中。

????只有在調用線程擁有某個對象的獨占鎖時,才能夠調用該對象的wait(),notify()和notifyAll()方法。如果嘗試在未獲取對象鎖時調用這三個方法,那么你將得到一個"java.lang.IllegalMonitorStateException:current thread not owner"。

????當一個線程正在某一個對象的同步方法中運行時調用了這個對象的wait()方法,那么這個線程將釋放該對象的獨占鎖并被放入這個對象的等待隊列,(JZ:意味著其他線程也可以再次調用同一個對象的wait方法)

  注意,wait()方法強制當前線程釋放對象鎖。這意味著線程在調用某對象的wait()方法之前,當前線程必須已經獲得該對象的鎖。因此,線程必須在某個對象的同步方法或同步代碼塊中才能調用該對象的wait()方法。wait方法是native方法,里面的實現細節不清楚,但是線程A調用某對象B的wait方法肯定默認線程A已經擁有了某對象B的鎖(能夠進入同步方法或同步代碼塊就說明線程A競爭到了對象鎖)。如果跟這種默認(競爭得到鎖)沖突,那么JVM就會報出運行時錯誤IllegalMonitorStateException(RuntimeException)。

  當某線程調用某對象的 notify()或notifyAll()方法時,任意一個(對于notify())或者所有(對于notifyAll())在該對象的等待隊列中的線程,將被轉移到該對象的入口隊列。接著這些隊列(譯者注:可能只有一個)將競爭該對象的鎖,最終獲得鎖的線程繼續執行。

如果沒有線程在該對象的等待隊列中等待獲得鎖,那么notify()和notifyAll()將不起任何作用。在調用對象的notify()和notifyAll()方法之前,調用線程必須已經得到該對象的鎖。因此,必須在某個對象的同步方法或同步代碼塊中才能調用該對象的notify()或notifyAll()方法。

  對于處于某對象的等待隊列中的線程,只有當其他線程調用此對象的notify()或notifyAll()方法時才有機會繼續執行。

  調用wait()方法的原因通常是,調用線程希望某個特殊的狀態(或變量)被設置之后再繼續執行。調用notify()或notifyAll()方法的原因通常是,調用線程希望告訴其他等待中的線程:"特殊狀態已經被設置"。這個狀態作為線程間通信的通道,它必須是一個可變的共享狀態(或變量)。

例如,生產者線程向緩沖區中寫入數據,消費者線程從緩沖區中讀取數據。消費者線程需要等待直到生產者線程完成一次寫入操作。生產者線程需要等待消費者線程完成一次讀取操作。假設wait(),notify(),notifyAll()方法不需要加鎖就能夠被調用。

此時消費者線程調用wait()正在進入狀態變量的等待隊列(譯者注:可能還未進入)。在同一時刻,生產者線程調用notify()方法打算向消費者線程通知狀態改變。那么此時消費者線程將錯過這個通知并一直阻塞。因此,對象的wait(),notify(),notifyAll()方法必須在該對象的同步方法或同步代碼塊中被互斥地調用。

[JZ]:這也是多線程編程里的一個經典問題,線程A進行鎖操作的過程是非原子的,線程B就進行了釋放的請求,導致線程A申請鎖后無法釋放!

參考網頁

http://www.cnblogs.com/jiangz222/p/4719671.html

http://www.blogjava.net/freeman1984/archive/2011/10/14/361306.html

join方法源碼分析

jdk源碼

/*** Waits at most {@code millis} milliseconds for this thread to* die. A timeout of {@code 0} means to wait forever.** <p> This implementation uses a loop of {@code this.wait} calls* conditioned on {@code this.isAlive}. As a thread terminates the* {@code this.notifyAll} method is invoked. It is recommended that* applications not use {@code wait}, {@code notify}, or* {@code notifyAll} on {@code Thread} instances.** @param millis* the time to wait in milliseconds** @throws IllegalArgumentException* if the value of {@code millis} is negative** @throws InterruptedException* if any thread has interrupted the current thread. The* <i>interrupted status</i> of the current thread is* cleared when this exception is thrown.*/public final synchronized void join(long millis) throws InterruptedException {long base = System.currentTimeMillis();long now = 0;if (millis < 0) {throw new IllegalArgumentException("timeout value is negative");}if (millis == 0) {while (isAlive()) {wait(0);}} else {while (isAlive()) {long delay = millis - now;if (delay <= 0) {break;}wait(delay);now = System.currentTimeMillis() - base;}}}

join不帶參數源碼分析1--實質上是調用了wait方法

join()方法實質上就是join(0),最終執行代碼如下所示

實質上調用代碼1就相當于調用代碼2

join帶參數源碼分析

核心代碼

變一下:

while?(isAlive()) {

????????????if?(millis?<= now) {

????????????????break;

????????????}

????????????wait(millis?- now);

????????????now?= System.currentTimeMillis() - base;

????????}

分析

base和now都是時間。base是剛執行代碼時的時間,now是執行代碼流逝的時間。判斷mills時間是否流逝完畢,流逝完畢則break跳出代碼。

?

?

?

轉載于:https://my.oschina.net/u/3866531/blog/2242220

總結

以上是生活随笔為你收集整理的Thread源码分析之join方法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。