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

猜你喜欢

转载自blog.csdn.net/xlecho/article/details/82014862