執行緒方法join
xl_echo編輯整理,歡迎轉載,轉載請宣告文章來源。更多IT、程式設計案例、資料請聯絡QQ:1280023003,加群298140694。百戰不敗,依不自稱常勝,百敗不頹,依能奮力前行。——這才是真正的堪稱強大!!!
執行緒的方法join,其實就是一個多執行緒相互制約的的行為。如:當執行緒A使用join,同事執行的執行緒B就會等待,知道A執行緒的生命週期結束。但是這個例子有個前提,需要至少兩條以上的執行執行緒,並且這兩條執行緒要有執行緒呼叫。
在Thread的原始碼中我們可以看到join的實現。
/**
* 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;
}
}
}
/**
* Waits at most {@code millis} milliseconds plus
* {@code nanos} nanoseconds for this thread to die.
*
* <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
*
* @param nanos
* {@code 0-999999} additional nanoseconds to wait
*
* @throws IllegalArgumentException
* if the value of {@code millis} is negative, or the value
* of {@code nanos} is not in the range {@code 0-999999}
*
* @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, int nanos)
throws InterruptedException {
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}
if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
millis++;
}
join(millis);
}
/**
* Waits for this thread to die.
*
* <p> An invocation of this method behaves in exactly the same
* way as the invocation
*
* <blockquote>
* {@linkplain #join(long) join}{@code (0)}
* </blockquote>
*
* @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 void join() throws InterruptedException {
join(0);
}
可以看到的是該方法被三次過載。作用如下:
- 第一個被使用會在該執行緒會給該執行緒執行完成的優先權。
- 第二個被使用會讓該執行緒在多少毫秒之內有優先權。
- 第三個被使用會讓該執行緒在多少毫秒和多少納秒之內擁有優先權。比第二個更精確。
仔細閱讀我們不難發現join底層其實是呼叫了wait()方法,實現的時候就是讓呼叫程進入了A物件的等待池,等到A物件執行完成之後,呼叫的執行緒才能出來去掉用B執行緒。
我們可以通過一個例項來看看
package com.echo.es.demoes.JavaApi;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* @Author xl_echo
* @Date 2018/8/15 下午8:30
**/
@Configuration
public class TestClient {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
while (true) {
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "執行緒執行中");
}
});
Thread t2 = new Thread(() -> {
while (true) {
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "執行緒執行中");
}
});
t1.start();
// t1.join();
t2.start();
// t2.join();
System.out.println("main執行緒結束");
}
}
當t1.join()和t2.join()全部註釋掉的時候我們可以看到控制檯輸出效果如下:main執行緒並沒有因為死迴圈而不繼續往下執行,而是在呼叫之後結束,但是t1和t2在不間斷執行。
當我們開啟t1.join()的時候我們可以看到main執行緒一直沒有被結束,控制檯資料的結果是顯示t1一直在執行。其實是main執行緒一直等待t1執行完成。
但是當我們註釋掉t1.join(),開啟t2.join()的註釋時,我們可以我們可以看到t1一直在執行,但是t2也一直在執行。輸出結果如下:
很多人在這裡有誤解,以為開啟t2.join()的時候,t1不會執行,main也會一直等待,其實這是執行緒的主從關係沒有理解清楚。當我們開啟t2.join()的註釋時,main呼叫玩t1,會繼續呼叫t2,但是t2使用了join方法,所以這個時候main執行緒會進入t2的等待池,等待t2結束,main才會結束。但是t1呢?他是一個已經被啟動的執行緒,如果沒有結束,不管t2的狀態如何,他都會繼續執行。
總結:
所以到這裡我們不難看出,執行緒的join方法,其實就是讓呼叫執行緒等待。