Thread的join()方法解析

24 篇文章 0 订阅
6 篇文章 0 订阅

一般用join方法实现主线程等待其他异步线程完成,今天就看看它到底是咋实现的。

先看下示例


  // 子线程
  static class SleepThread implements Runnable {
        @Override
        public void run() {
            try {
                System.out.println("子线程开始");
                Thread.sleep(1000);
                System.out.println("子线程结束");
            } catch (InterruptedException e) {
               // 忽略异常
            }
        }
    }
    
    public static void main(String[] args) {
        try {
            
            Thread t1 = new Thread(new SleepThread());
            // 开启子线程
            t1.start();
            // 让主线程main等待子线程t1
            t1.join();
            System.out.println("main over");
        } catch (Exception e) {
            e.printStackTrace();
        }  

这就是一般join方法的用法了。执行t1.join(); 后,主线程会在此处等待t1线程完成后再执行。来看看join()源码,分析下怎么实现的。


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

接着往下看

 
  // 注意join方法有synchronized修饰
  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) {
            // 主要是这里,不断判断是否存在,如果存活就调用wait
            // 下面看看它怎么判断存活的
            while (isAlive()) {
                wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

isAlive方法


   //是个native方法
   public final native boolean isAlive();

由上面可知,执行了join()方法后,就获得了该线程实例的synchronized锁(在例子中是t1),随后调用wait()方法进入等待状态。

关键是什么时会唤醒,谁会唤醒它的。

join方法注释上有

As a thread terminates the * {@code this.notifyAll} method is invoked

也就是说JVM会保证,当线程终结时,会调用notifyAll()方法唤醒所有等待该实例锁的对象。由此,join()机制就算是搞懂了。

不过,既然知道了join的机制,我们也可以实践一下


  public static void testJoin() throws InterruptedException {

        // t1线程会等待2秒
        Thread t1 = new Thread(new SleepThread());
        t1.start();
        
        // 获取t1的锁
        synchronized (t1) {
            //进入等待状态,等待t1结束唤醒它
            t1.wait();
        }
        System.out.println("main end");
    }

与源码join有不一样的地方,没有加isAlive的判断,没有用循环,如果你的程序没有在别的地方用t1这个锁,也没有地方用类似t1.notifyt1.notifyAll 的地方,那上面就可以。不过为了保险,还是用下面这个吧


   public static void testJoin() throws InterruptedException {

        // t1线程会等待2秒
        Thread t1 = new Thread(new SleepThread());
        t1.start();

        synchronized (t1) {
           // 用循环而不是if,也是为了防止其他地方唤醒了t1,而不是当t1线程结束的时候,即防止假唤醒
            while (t1.isAlive()) {
                t1.wait();
            }
        }
        System.out.println("main end");
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值