深入理解join方法的实现原理

有一道面试题是: 如何控制多线程的执行顺序;

线程的代码就不贴了。上伪码好了:

main(){
thread1.start();
thread1.join();
thread2.start();
thead2.join();
thread3.start();

}

有几个方法都可以做到,这里主要是套路最简单的使用join方法,如何解决。 首先看join方法的API 这是随手百度的 : join()等待线程结束。

都是很浅的说了一下,要深入理解还是得看源码:

public final synchronized void josin (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;
            }
        }
     }

因为join方法 是一个 synchronized 的同步方法。

举个例子,join是在main方法里被调用了。

然后main方法就持有了 join方法 的 这个锁。

然后join 方法里面调用了 wait方法。

这个过程的目的是让持有这个同步锁的线程进入等待。

那么谁持有了这个同步锁呢?

答案就是main方法,因为main方法调用了join方法。

main方法就持有 synchronized 标记的这个锁,谁持有这个锁谁就等待。

wait()方法只会让持有锁的线程进入等待,而启动线程的 start() 并没有持有锁,所以

strat方法还是会执行,而join方法中的wait方法 使main 方法等待了。

所以main方法就没有获取到CPU资源,

所以main方法中的 thread2 就没有办法获取CPU资源。

然后join方法执行完之后,不用想,JVM底层肯定执行了 notify的操作。

网上copy来的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就是当前线程main线程啊。
  lock.notify_all(thread);

  thread->clear_pending_exception();
}

notify_all 之后 join方法结束,自然 main方法又获取到cpu资源了,然后thread2又可以取得cpu资源,然后又是这个过程。

大概就是这样了

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏崔庆才的专栏

爬虫速度太慢?来试试用异步协程提速吧!

在执行一些 IO 密集型任务的时候,程序常常会因为等待 IO 而阻塞。比如在网络爬虫中,如果我们使用 requests 库来进行请求的话,如果网站响应速度过慢,...

52410
来自专栏钟绍威的专栏

从源代码到Runtime发生的重排序编译器重排序指令重排序内存系统重排序阻止重排序

 源代码和Runtime时执行的代码很可能不一样,这是因为编译器、处理器常常会为了追求性能对改变执行顺序。然而改变顺序执行很危险,很有可能使得运行结果和预想的不...

29990
来自专栏风中追风

深入理解join方法的实现原理

有几个方法都可以做到,这里主要是套路最简单的使用join方法,如何解决。 首先看join方法的API 这是随手百度的 : join()等待线程结束。

35370
来自专栏xcywt

《Linux命令行与shell脚本编程大全》第十一章 构建基本脚本

11.1使用多个命令 $date;who   //  命令列表,加入分号就可以,这样会依次执行。参见5.2.1节 注意区分$(date;who),这个是进程列表...

22170
来自专栏程序员同行者

django rest framework mixins小结

由上图可以看出这个类的一个逻辑,其中,perform_create( )对serializer直接进行save保存,当在一些情境下,我们需要对perform...

21830
来自专栏C/C++基础

Linux命令(1)——xargs命令

xargs可以将stdin中以空格或换行符进行分隔的数据,形成以空格分隔的参数(arguments),传递给其他命令。因为以空格作为分隔符,所以有一些文件名或者...

20030
来自专栏指尖下的Android

JNI之路径初探---3

这里讲一下如何拿到类中方法和属性的签名: 1,cmd进入命令行 2,cd 命令切到当前项目的src路径 3,javap -s -p 包名+类名(xxx.x...

11830
来自专栏zingpLiu

Python 【web框架】之Flask

flask 是Python实现的轻量级web框架。没有表单,orm等,但扩展性很好。很多Python web开发者十分喜欢。本篇介绍flask的简单使用及其扩展...

15920
来自专栏深度学习之tensorflow实战篇

整理ING

os.path.exists(img_name)(判断图片是否已经存在,如果存在就跳过) 很好的一篇爬虫实例:先保存下 用MongoDB数据库记录已下载过的...

29960
来自专栏技术专栏

慕课网Flask高级编程实战-3.蓝图、模型与CodeFirst

应该讲一些初始化工作,放在对应层级的包的初始化文件 __init__.py 中。比如Flask核心应用app对象初始化应该放在应用层级app包的 __init_...

29330

扫码关注云+社区

领取腾讯云代金券