0
点赞
收藏
分享

微信扫一扫

线程方法join


xl_echo编辑整理,

线程的方法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在不间断执行。

线程方法join_Thread

当我们打开t1.join()的时候我们可以看到main线程一直没有被结束,控制台数据的结果是显示t1一直在执行。其实是main线程一直等待t1执行完成。

线程方法join_Thread_02

但是当我们注释掉t1.join(),打开t2.join()的注释时,我们可以我们可以看到t1一直在执行,但是t2也一直在执行。输出结果如下:

线程方法join_elasticsearch_03

很多人在这里有误解,以为打开t2.join()的时候,t1不会执行,main也会一直等待,其实这是线程的主从关系没有理解清楚。当我们打开t2.join()的注释时,main调用玩t1,会继续调用t2,但是t2使用了join方法,所以这个时候main线程会进入t2的等待池,等待t2结束,main才会结束。但是t1呢?他是一个已经被启动的线程,如果没有结束,不管t2的状态如何,他都会继续执行。

总结:


所以到这里我们不难看出,线程的join方法,其实就是让调用线程等待。




举报

相关推荐

0 条评论