Thread中join()使用

一. 使用方式

Thread thread = new Thread(“[test] thread”);
thread.start();
thread.join();

二. 为啥要用join()

比如当子线程中业务逻辑处理的时间很长时,那么主线程就会先于子线程提前结束,而如果想要主线程在子线程处理完以后再结束(比如需要子线程中返回的数据),那就可以使用 Thread threadSon.join();

三. 作用

join()上面的解释:

Waits for this thread to die.

当前线程指得是子线程,即阻塞主线程继续执行,直到子线程处理结束;

四. 实例
public class ThreadTest {
    public static void main(String[] args) throws InterruptedException {
        String mainThread = Thread.currentThread().getName();
        System.out.println(mainThread + " start..");
        ThreadB threadB = new ThreadB();
        threadB.start();
        threadB.join();
        System.out.println(mainThread + " end..");
    }
}


public class ThreadB extends Thread {
    public ThreadB() {
        super("[ThreadB] thread");
    }

    public void run() {
        String threadName = Thread.currentThread().getName();
        System.out.println(threadName + " start..");
        for(int i=0;i<5;i++) {
            System.out.println(threadName + " loop at 0" + i);
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(threadName + " end..");
    }
}


执行结果:

main start..
[ThreadB] thread start..
[ThreadB] thread loop at 00
[ThreadB] thread loop at 01
[ThreadB] thread loop at 02
[ThreadB] thread loop at 03
[ThreadB] thread loop at 04
[ThreadB] thread end..
main end..
五. 源码解析

jdk中join()的源码:

public final void join() throws InterruptedException {
	join(0);
}

主要是接下来的 join(long millis)

/**
* Waits at most {@code millis} milliseconds for this thread to
* die. A timeout of {@code 0} means to wait forever.
*/
public final synchronized void join(long millis)    //注意这里的synchronized
throws InterruptedException {
	long base = System.currentTimeMillis();
	long now = 0;

	if (millis < 0) {
		throw new IllegalArgumentException("timeout value is negative");
	}
    //如果millis为0的话,只要线程(上面的子线程ThreadB)还活着,就会调用wait(0)阻塞当前线程,
    //一直到threadB执行结束;(wait(0)相当于持有threadB线程的锁然后等待)
	if (millis == 0) {
		while (isAlive()) {
			wait(0);
		}
	} else {
		while (isAlive()) {
			long delay = millis - now;
			if (delay <= 0) {
				break;
			}
			wait(delay);
			now = System.currentTimeMillis() - base;
		}
	}
}

六. 我的感想

我刚刚是在springboot启动过程中的源码才注意到的():

private void refreshContext(ConfigurableApplicationContext context) {
	refresh(context);
	if (this.registerShutdownHook) {
		try {
        //看到了这里
			context.registerShutdownHook();
		}
		catch (AccessControlException ex) {
			// Not allowed in some environments.
		}
	}
}

然后跟着context.registerShutdownHook();继续挖掘,直到看到了这个类ApplicationShutdownHooks,它里面的runHooks()方法如下:

static void runHooks() {
	Collection<Thread> threads;
	synchronized(ApplicationShutdownHooks.class) {
		threads = hooks.keySet();
		hooks = null;
	}

	for (Thread hook : threads) {
		hook.start();
	}
	for (Thread hook : threads) {
		try {
        //看到了这个join()方法
			hook.join();
		} catch (InterruptedException x) { }
	}
}

然后就深入地了解下join()方法,从一个地方拓展到其他地方;

我以前也有过类似需要等待子线程执行完,然后执行主线程的需求,当时应该是直接让主线程等待的。。然后再看去探查指定的指标是否完成……有了这个threadB.join()方法,这样就合理多了,避免了主线程等待时的空自旋;

六. 参考文章

https://blog.csdn.net/sinat_29384657/article/details/52228578

https://zhuanlan.zhihu.com/p/258581678

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值