java中join()方法的等价写法分析

join()的用法:join()方法是调用者轮询来查看该线程的alive状态,调用者使用 t1.join()来等待t1线程结束。

join()源码

	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;
            }
        }
    }

t1.join()的等价写法:

synchronized (t1) {
	// 调用者线程进入 t1 的 waitSet 等待, 直到 t1 运行结束
	while (t1.isAlive()) {
	t1.wait(0);
 }
}

完整的代码

public static void main(String[] args) throws Exception {
		Thread t1 = new Thread(() -> {
			System.out.println("t1先执行");
		}, "t1");

		Thread t2 = new Thread(() -> {
			try {
				synchronized (t1) {
				// 调用者线程进入 t1 的 waitSet 等待, 直到 t1 运行结束
					while (t1.isAlive()) {
						t1.wait(0);
					}
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("t2后执行");
		}, "t2");
		t1.start();
		t2.start();
	}

打印:

t1先执行
t2后执行

刚开始的时候我是很懵逼的,因为可以发现,t1.wait(0)后【把t1直接看成一个普通对象,此时t2线程释放对象锁进入WAITING状态】,并没有相应的notifyAll()/notify()方法来将t2线程唤醒,那为什么能够打印"t2后执行"呢?

这里的一个重大知识点是,t1.wait()后是如何唤醒线程的?

通过看join()的文档:

As a thread terminates the {@code this.notifyAll} method is invoked。 当一个线程终止时,notifyAll方法会被调用。

所以,当t1线程终止时,会隐式地调用t1.notifyAll()方法,从而唤醒了t2线程,让t2的代码继续执行。

`join()` 方法是 `Thread` 类的一个方法,它的作用是让调用该方法的线程等待该线程执行完毕。当一个线程使用 `join()` 方法时,调用线程会被阻塞,直到被调用线程执行完毕后才会继续执行。 下面是 `join()` 方法的源码: ``` public final void join() throws InterruptedException { join(0); } ``` 可以看到,`join()` 方法实际上是调用了另一个重载方法 `join(long millis)`,并将参数设置为 0。 ``` 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; } } } ``` 可以看到,`join(long millis)` 方法是一个同步方法,它首先对传入的参数进行检查,如果小于 0,则会抛出异常。 如果传入的参数为 0,则调用 `wait(0)` 方法,这会使当前线程进入等待状态,直到被调用线程执行完毕后才会被唤醒。 如果传入的参数不为 0,则会在循环检查被调用线程是否还活着,如果还活着,则调用 `wait(delay)` 方法,这会使当前线程进入等待状态,等待一定的时间后被唤醒。在每次循环,都会更新当前时间 `now`,并计算需要等待的时间 `delay`。 如果被调用线程已经执行完毕或者等待时间已经超过了传入的参数,则会跳出循环,方法执行完毕。 总的来说,`join()` 方法的本质是利用了 `wait()` 和 `notify()` 方法实现线程的同步和等待。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值