从天圆地方到地球是圆的,从地心说到日心说,一个个思想模型的提出,都成功演奏了问题,假设,验证三部曲。所以我们就使用这些先哲留给我们的探索宇宙的思维方式——问题,假设,验证三部曲,来探究一下Java中Thread类的join方法到底是如何实现等待的。 |
---|
三部曲第一弹
问题
如何实现Thread.join()方法假设
一个最简单的实现方式,就是不断循环判断加入线程是否还在执行,直到停止运行,跳出循环,当前线程继续运行验证
public class MyThread extends Thread {
/**
* 自定义的join方法
*/
public final void join2() {
while (this.isAlive()) ;
}
@Override
public void run() {
try {
sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("my thread run over");
}
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
myThread.join2();
System.out.println("main thread run over");
}
}
在这个示例中,如果“my thread run over”打印在“main thread run over”之前就算验证成功
运行结果:
可见这个假设验证成功
三部曲第二弹
问题
通过这种不断循环判断的方式,可以实现让当前线程等待的功能,但是,线程会处于忙等待状态,CPU始终在空转,造成了不必要的性能开销
假设
通过调用wait方法,释放处理机,避免“忙等”状态
验证
public class MyThread extends Thread {
/**
* 自定义的join方法
*/
public final void join2() {
while (this.isAlive()) ;
}
/**
* 自定义的join方法
* 可以释放CPU
*/
public final synchronized void join3() throws InterruptedException {
while (this.isAlive()) {
wait();
}
}
@Override
public void run() {
try {
sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("my thread run over");
}
public static void main(String[] args) throws InterruptedException {
MyThread myThread = new MyThread();
myThread.start();
//myThread.join2();
myThread.join3();
System.out.println("main thread run over");
}
}
可见,通过wait方法避免“忙等”是可行的
三部曲第三弹
问题
有wait,必有notify,可是在JDK中并不能找到对myThread线程的notify调用
假设
notify是jvm调用的
验证
jvm源码片段:
//一个c++函数:
void JavaThread::exit(bool destroy_vm, ExitType exit_type);
//这家伙是啥,就是一个线程执行完毕之后,jvm会做的事,做清理啊收尾工作,
//里面有一个贼不起眼的一行代码,眼神不好还看不到的呢,就是这个:ensure_join(this);
//翻译成中文叫 确保_join(这个);代码如下:
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);
//同志们看到了没,别的不用看,就看这一句
//thread就是当前线程,是啥是啥?就是myThread线程啊。
lock.notify_all(thread);
thread->clear_pending_exception();
}
所以,notify就是由jvm在线程执行结束后调用的
最后,再来看一下JDK的源码实现
以下是jdk_1.8.0.161中,java.lang.Thread类的源码片段:
public final void join() throws InterruptedException {
join(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;
}
}
}
仔细观察第二段源码中的第11、12行,可见,源码当中正是这样实现的。
我们的探索告一段落,下次再见!
参考资料: