多线程通信(四)join()方法的使用

本文探讨了在多线程环境中,如何使用join()方法确保主线程等待子线程执行完毕后再继续运行。通过实例代码和源码分析,揭示了join()方法的实现原理,即利用wait()方法实现线程间的同步,并指出带参数的join()方法可设置等待时间。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        开发中常常会遇见这样的问题,主线程在运行的时候,需要一些子线程去进行相应的运算,如果主线程需要子线程提供一个处理后的数据,那么主线程就必须要等子线程运行完后才能继续执行。先看下面的这种情况

影视作品的一个拍摄场景中,这次不是主角(主线程)的独角戏,他需要一个配角(子线程)来搭戏,但是配角还没来尴尬,主角只能等配角来了才能开始,要是配角没来,主角非要开始的话那这个场景的戏就乱了。

public class SupportRule extends Thread{

    @Override
    public void run(){

        try{

            System.out.println("配角赶路中……");
            Thread.sleep(5000);
            System.out.println("配角来啦!!!马上化妆");
            Thread.sleep(5000);
        } catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}
public class JoinTest {

    public static void main(String[] args){

        SupportRule supportRule = new SupportRule();
        supportRule.start();

        System.out.println("我是主角先拍我!!!");
        System.out.println("今天要有一个配角给你配戏才行啊,我看看配角到了没!");
        System.out.println("我不管,我现在就要开拍!!!");
        System.out.println("开拍……");
    }
}

运行结果,额,这还让导游怎么拍。


这时就需要使用join()方法(当然,也可以使用强大的并发工具包)

 join()方法定义在Thread类中,JDK中给出的定义就是等待该线程终止,那么可以在子线程中使用join()方法,实现主线程等待子线程执行完后在执行主线程的效果。

现在通过代码看下

public class JoinTest {

    public static void main(String[] args){

        try{
            SupportRule supportRule = new SupportRule();
            supportRule.start();
            supportRule.join();
            System.out.println("我是主角先拍我!!!");
            System.out.println("今天要有一个配角给你配戏才行啊,我看看配角到了没!");
            System.out.println("我不管,我现在就要开拍!!!");
            System.out.println("开拍……");
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}
嗯,这次导演很满意。


继续深入看看join()方法的实现

反编译,有参的话等待相应的milliseconds后该线程死亡,无参的话(millis=0)则一直等待(直到该线程执行完成)。

/**
     * 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) {  // join()方法不传参数时,millis为0进入该分支
            while (isAlive()) {
                wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

现在来看看这部分代码

while (isAlive()) { // 判断线程是否处于活动状态,也就是如果配角线程还活着,主角线程就要等,我去,到底谁是主角!!!
     wait(0);
}

而且join方法是final的synchronized方法,那就说明配角线程要在主角线程里面搞事情啊,那没办法了,你搞就搞吧,记得最后唤醒我就行了,我妥协还不行。但是在join()方法里面并没有任何唤醒操作啊,继续挖,挖到JVM源码抓狂

任何Java线程在执行完后都会执行一个C++函数

void JavaThread::exit(bool destroy_vm, ExitType exit_type)
里面调用了一个
ensure_join(this);

然后注意这个方法里面的notifyAll()

static void ensure_join(JavaThread* thread) {
  Handle threadObj(thread, thread->threadObj());

  ObjectLocker lock(threadObj, thread);

  thread->clear_pending_exception();

  java_lang_Thread::set_thread_status(threadObj(), java_lang_Thread::TERMINATED);

  java_lang_Thread::set_thread(threadObj(), NULL);

  lock.notify_all(thread);

  thread->clear_pending_exception();
}

所以,join()方法的实现原理是使用wait()方法实现的,它达到的效果其实和使用synchronized类似,区别就是synchronized使用的是对象监听器。

join()方法还可传参,只等待指定的时间

public class JoinTest {

    public static void main(String[] args){

        try{
            SupportRule supportRule = new SupportRule();
            supportRule.start();
            supportRule.join(4000);
            System.out.println("我是主角先拍我!!!");
            System.out.println("今天要有一个配角给你配戏才行啊,我看看配角到了没!");
            System.out.println("我不管,我现在就要开拍!!!");
            System.out.println("开拍……");
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

等待4秒回,主角开拍


评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值