Java并发编程之join方法的使用

简介

在多线程编程中,有时候一个线程的执行可能要依赖于另外一个线程的执行结果才能执行,JDK提供了join方法来实现这种功能。

当我们在线程上调用join方法时,调用线程进入等待状态。它保持等待状态,直到引用的线程执行完成。

join及其重载方法:

  1. join(),等待该线程执行结束。
  2. join(long millis),类似join()方法,多了一个millis参数,表示最多等待该线程执行的毫秒数,join(0)等价于join()。
  3. join(long millis, int nanos),同join(long millis)方法,只是等待时间有了更高的精度。

join方法的基本使用

等待子线程结束,主线程再继续执行:

public class Demo {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("数据加载中...");
        });

        thread.start();
        thread.join();

        System.out.println("数据加载完毕");
    }
}

输出结果:

数据加载中...
数据加载完毕

设置最长等待时间,超过该时间后,主线程将继续执行,而不会等子线程结束再执行:

public class Demo {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("数据加载中...");
        });

        thread.start();
        thread.join(1000);

        System.out.println("数据加载完毕");
    }
}

输出结果:

数据加载完毕
数据加载中...

join方法源码

join方法源码如下:

public final synchronized void join(long millis)throws InterruptedException {
	long base = System.currentTimeMillis();
	long now = 0;

	//等待时间小于0直接抛出IllegalArgumentException异常
	if (millis < 0) {
		throw new IllegalArgumentException("timeout value is negative");
	}

	//等待时间为0,调用wait(0),一直等待线程结束。(join(0)等于调用wait(0)等于调用wait())
	if (millis == 0) {
		while (isAlive()) {
			wait(0);
		}
	} else {
		//等待时间大于0时,即使中途被唤醒,只要没超过等待时间,依旧会进入等待状态。
		while (isAlive()) {
			long delay = millis - now;
			if (delay <= 0) {
				break;
			}
			wait(delay);
			now = System.currentTimeMillis() - base;
		}
	}
}

从join方法源码可以看出,join方法的本质是调用线程对象的wait方法,调用join方法时需要获取到线程对象的锁,然后调用线程对象的wait方法,在线程结束后会自动调用线程对象的notifyAll方法

所以当我们在做同步处理时,应该避免使用Thread对象作为锁对象,因为这有可能会影响系统api的工作。

原文地址:https://www.cnblogs.com/seve/p/14520059.html