join()方法实例演示及源码分析

join()方法实例演示及源码分析

以下为测试代码,下文围绕该代码展开:

public class MyThread1 implements Runnable {
    public void run() {
        System.out.printf("Beginning MyThread1: %s\n", new Date());
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.printf("MyThread1 has finished: %s\n", new Date());
    }
}

public class MyThread2 implements Runnable {
	public void run() {
        System.out.printf("Beginning MyThread2: %s\n", new Date());
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.printf("MyThread2 has finished: %s\n", new Date());
    }

    public static void main(String[] args) {
        MyThread1 myThread1 = new MyThread1 ();
        Thread thread1 = new Thread(myThread1, "MyThread1");

        MyThread2 myThread2 = new MyThread2 ();
        Thread thread2 = new Thread(myThread2, "MyThread2 ");
        
		thread1.start();
        thread2.start();
		try {
            thread1.join();
            thread2.join(1800);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.printf("Main: Configuration has been loaded: %s\n", new Date());
    }
}

分析:thread1.start(); thread2.start(); 两个线程开启,抢占CPU资源顺序无法确定,所以第一句执行的语句无法确定。

继续 thread1.join(); 此时进入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;
            }
        }
    }

主要分析:

public final synchronized void join(long millis)
    throws InterruptedException {
        while (isAlive()) {
            wait(0);
        }

主线程获取join()方法的锁,判断thread1线程是否存活,若存活则则调用wait()方法,wait()方法只会让持有锁的线程进入等待,因此主线程阻塞,进入等待(join方法会造成当前线程wait,就如你看到的这里的wait(0),是当前线程wait,并不是调用者wait)。所以2s之后thread1的结束线程语句打印,主线程被唤醒,继续执行thread2.join(1800); 主线程继续阻塞,当过了1.8s之后,thread2依然没有执行完毕,从源码可知,此时会break,主线程被唤醒,继续执行完主线程结束语句,最后才会执行thread2执行结束语句。

打印结果:

Beginning MyThread1: Thu Jul 11 17:04:37 CST 2019
Beginning MyThread2: Thu Jul 11 17:04:37 CST 2019
MyThread1 has finished: Thu Jul 11 17:04:39 CST 2019
Main: Configuration has been loaded: Thu Jul 11 17:04:40 CST 2019
MyThread2 has finished: Thu Jul 11 17:04:41 CST 2019

或者:

Beginning MyThread2: Thu Jul 11 17:05:18 CST 2019
Beginning MyThread1: Thu Jul 11 17:05:18 CST 2019
MyThread1 has finished: Thu Jul 11 17:05:20 CST 2019
Main: Configuration has been loaded: Thu Jul 11 17:05:22 CST 2019
MyThread2 has finished: Thu Jul 11 17:05:22 CST 2019

至于thread1执行完毕,主线程被唤醒,但是从上面上源代码里并没有看到notify调用,而且文档上表明不建议应用程序自己去调用,最终答案在jvm C++源码里,源码之下:

void JavaThread::run() {
  ...
  thread_main_inner();
}

void JavaThread::thread_main_inner() {
  ...
  this->exit(false);
  delete this;
}

void JavaThread::exit(bool destroy_vm, ExitType exit_type) {
  ...
  // Notify waiters on thread object. This has to be done after exit() is called
  // on the thread (if the thread is the last thread in a daemon ThreadGroup the
  // group should have the destroyed bit set before waiters are notified).
  ensure_join(this);
  ...
}

static void ensure_join(JavaThread* thread) {
  // We do not need to grap the Threads_lock, since we are operating on ourself.
  Handle threadObj(thread, thread->threadObj());
  assert(threadObj.not_null(), "java thread object must exist");
  ObjectLocker lock(threadObj, thread);
  // Ignore pending exception (ThreadDeath), since we are exiting anyway
  thread->clear_pending_exception();
  // Thread is exiting. So set thread_status field in  java.lang.Thread class to TERMINATED.
  java_lang_Thread::set_thread_status(threadObj(), java_lang_Thread::TERMINATED);
  // Clear the native thread instance - this makes isAlive return false and allows the join()
  // to complete once we've done the notify_all below
  java_lang_Thread::set_thread(threadObj(), NULL);
  lock.notify_all(thread);
  // Ignore pending exception (ThreadDeath), since we are exiting anyway
  thread->clear_pending_exception();

重点看ensure_join 方法里的 lock.notify_all(thread);语句代码说明jvm会在线程B执行完成后帮我们调用notify_all()方法,这样主线程就会重回Runnable状态,时间片分配后主线程可执行join方法之后的代码。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值