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方法,其实就是让调用线程等待。