一、join()方法的使用

主线程创建并启动子线程,如果自线程中要进行大量的耗时运算,主线程往往将早于子线程结束之前结束。如果主线程想等待子线程执行完成之后再结束,比如子线程处理一个数据,主线程要取得这个数据中的值,就要用到 join() 方法

先来看一个不用 join() 方法的例子

public class MyThread extends Thread {@Overridepublic void run() {try {int secondVal = 2000;System.out.println(secondVal);Thread.sleep(secondVal);} catch (InterruptedException e) {e.printStackTrace();}}public static void main(String[] args) {MyThread myThread = new MyThread();myThread.start();System.out.println("我想当 myThread 对象执行完毕之后我在执行");System.out.println("但上面代码中的 sleep 中的值应该写多少呢?");System.out.println("答案是:不能确定");}}

结果是:

我想当 myThread 对象执行完毕之后我在执行
但上面代码中的 sleep 中的值应该写多少呢?
答案是:不能确定
run...

从结果看到,主线程 Main 在子线程 Thread-0 执行完之前就已经执行结束了,如果我们想要让主线程 Main 在子线程 Thread-0 执行结束之后在执行,join() 就派上用场了

public class MyThread1 extends Thread {@Overridepublic void run() {try {int time = 2000;System.out.println(Thread.currentThread().getName() + " 执行:"+ time / 1000 + "s");Thread.sleep(time);} catch (InterruptedException e) {e.printStackTrace();}}public static void main(String[] args) throws InterruptedException {MyThread1 myThread1 = new MyThread1();myThread1.start();myThread1.join();System.out.println("我想当 myThread 对象执行完毕之后我在执行");System.out.println(System.currentTimeMillis());}
}

结果是:

Thread-0 执行:2s
我想当 myThread 对象执行完毕之后我在执行

从结果看到,线程 Thread-0,即子线程先执行了,而主线程 Main 在子线程执行完才执行。join() 方法使调用这个方法的线程 Thread-0 正常执行 run() 方法,而使 Thread-0 所在的线程 main 进行无限期的阻塞,等待线程 Thread-0 销毁后(执行完 run 方法后)再继续执行线程 main 后面的代码

因此,join() 方法使得调用该方法的那段代码所在的线程暂时阻塞

二、join()方法和sleep()方法的区别

Thread.sleep(long) 方法的作用是让当前执行的线程休眠,当前执行的线程指的是 Thread.currentThread() 返回的线程,据JDK API的说法,“该线程不丢失任何监视器的所属权”,简单说就是 sleep 代码上下文如果被加锁了,锁依然在,但是CPU资源会让出给其他线程。简单的说,就是 sleep 方法并不释放锁,但是会让出 CPU 资源

class ThreadB2 extends Thread {@Overridepublic void run() {synchronized (this) {System.out.println(Thread.currentThread().getName() + " beg "+ System.currentTimeMillis());System.out.println(Thread.currentThread().getName() + " end "+ System.currentTimeMillis());}}
}class ThreadA2 extends Thread {private ThreadB2 threadB2;public ThreadA2(ThreadB2 threadB2) {this.threadB2 = threadB2;}@Overridepublic void run() {synchronized (threadB2) {System.out.println(Thread.currentThread().getName() + " beg "+ System.currentTimeMillis());try {Thread.sleep(4000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + " end "+ System.currentTimeMillis());}}
}public class Run2 {public static void main(String[] args) {ThreadB2 threadB2 = new ThreadB2();threadB2.setName("BBB");ThreadA2 threadA2 = new ThreadA2(threadB2);threadA2.setName("AAA");threadA2.start();threadB2.start();}}

结果是:

AAA beg 1540712329189
AAA end 1540712333189
BBB beg 1540712333189
BBB end 1540712333189

从结果可以看到,线程 AAA 先执行 run 方法中的语句,等到线程 AAA 的 run 方法执行结束后,线程 BBB 才可以执行自己 run 方法中的代码
由于两个线程持有同一个对象锁 threadB2,因此当一个线程持有对象锁的时候,如果该线程没有释放锁,那么另一个线程也没法执行同步块中的方法。当线程 AAA 输出第一条语句后,第二条语句在 4s 之后才开始执行,这说明对象锁一直被线程 AAA 持有,即 Thread.sleep(long) 方法是不释放对象锁的

那么对于 join() 方法呢?我们把上面的代码稍作修改,只将 ThreadA2 中的 run 方法修改一番

class ThreadB2 extends Thread {@Overridepublic void run() {synchronized (this) {System.out.println(Thread.currentThread().getName() + " beg "+ System.currentTimeMillis());System.out.println(Thread.currentThread().getName() + " end "+ System.currentTimeMillis());}}
}class ThreadA2 extends Thread {private ThreadB2 threadB2;public ThreadA2(ThreadB2 threadB2) {this.threadB2 = threadB2;}@Overridepublic void run() {synchronized (threadB2) {System.out.println(Thread.currentThread().getName() + " beg "+ System.currentTimeMillis());try {System.out.println("wait之前:" + threadB2.isAlive());threadB2.join();System.out.println("wait 之后" + threadB2.isAlive());} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + " end "+ System.currentTimeMillis());}}
}public class Run2 {public static void main(String[] args) {ThreadB2 threadB2 = new ThreadB2();threadB2.setName("BBB");ThreadA2 threadA2 = new ThreadA2(threadB2);threadA2.setName("AAA");threadA2.start();threadB2.start();}}

结果是:

AAA beg 1540817368955
wait之前:true
BBB beg 1540817368956
BBB end 1540817368956
wait之后:false
AAA end 1540817368956

单从结果来看,线程 AAA 执行了一半,就停止了,然后线程 BBB 在执行,最后线程 AAA 执行 join() 方法后面的代码。如果不直到 join() 方法的实现的话,也能根据结果推荐,join() 方法是释放锁,而且和 wait() 方法的作用类似,因为 wait() 方法已经在这篇(https://blog.csdn.net/babycan5/article/details/83513832)讲得比较详细,所以这里我只从 join() 源码的来看(虽然也是使用 wait 来实现的…)

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");}//语句1if (millis == 0) {while (isAlive()) {wait(0);}} else {while (isAlive()) {long delay = millis - now;if (delay <= 0) {break;}wait(delay);now = System.currentTimeMillis() - base;}}
}

这下看的更明显了,这不还是使用 wait() 方法嘛!!!注意上面的语句1,它省略了一部分,我依据这个例子把缺的补上,然后分析。这里只需要注意两点, while 语句中的 isAlive() 到底是谁调用的?和下面的 wait(0) 是谁调用的?

例子中使用 threadB2.join() ,根据上面的例子,对象 threadB2 是对象锁,线程 AAA 持有该对象锁,首先在 while 的判断中执行 threadB2.isAlive(),即判断 threadB2 对应的线程 BBB 是否存活,如果线程 BBB 还活着,就用锁对象 threadB2 调用 wait() 方法,即 threadB2.wait(0)该锁对象被释放,同时,拥有 thradB2 锁对象的那个线程 AAA 进入等待状态 (很重要!!!),之后,线程 BBB 拿到对象锁,执行自己同步方法块中的代码,等到线程 BBB 执行结束,系统会自动调用 threadB2.notifyAll(),唤醒正在等待对象锁的线程 AAA,然后线程 AAA 才可以继续执行后面的代码

需要注意我加粗的那段文字,足以解释上面那个例子的结果了

因此,对比 sleep() 和 join() 方法,得出一个结论

  • Thread.sleep(long) 方法不释放锁,只是会暂时让出 CPU 资源,如果在同步方法中使用该方法,那么线程依然是同步执行的
  • join(long) 方法是会释放锁的,因为底层使用 wait() 方法来实现

三、参考

https://mp.weixin.qq.com/s/-VVlaSj0In1rDMN7thT6dQ

join()方法的使用相关推荐

  1. Python join()方法

    描述 Python join() 方法用于将序列中的元素以指定的字符连接生成一个新的字符串. 语法 join()方法语法: str.join(sequence).join(sequence) 参数 s ...

  2. java 线程 thread.join_java线程Thread的join方法。

    1,方法的作用: 父线程等待子线程的执行. 如果是join或者join(0),即等待时长是0,父线程就会一直等到子线程执行结束, 如果是join(time),即等待时长是time数值,那父线程实际等待 ...

  3. java进阶 线程池 join用法总结:thread4.join();方法,就表明thread4.join();这个线程受到贵客待遇,直到这个线程执行完,被插入这个方法的载体线程才可以执行。

    那个线程调用join 举例 thread4.join();方法,就表明thread4.join();这个线程受到贵客待遇,直到这个线程执行完,被插入这个方法的载体线程才可以执行. package ja ...

  4. java多线程中的join方法详解

    java多线程中的join方法详解 方法Join是干啥用的? 简单回答,同步,如何同步? 怎么实现的? 下面将逐个回答. 自从接触Java多线程,一直对Join理解不了.JDK是这样说的:join p ...

  5. java thread join_java中thread的join方法为什么能让线程插队

    在面试中经常会遇到这样的问题:在主线程中有两个子线程,如果能让着两个子线程能顺序的执行? 答案自然是用join来使得两个线程顺序执行,先看一下具体代码 public class ThreadOfJoi ...

  6. Oracle的join默认为,Oracle中的三种Join方法详解

    这里将为大家介绍Oracle中的三种Join方法,Nested loop join.Sort merge join和Hash join.整理出来以便帮助大家学习. 基本概念 Nested loop j ...

  7. 线程状态以及sleep yield wait join方法

    前言 在日常的开发过程中,我们通过会使用Thread.sleep模拟一个耗时的任务执行过程. 在深入理解这四个方法之前,首先对线程的状态进行理解阐述. 线程概念 线程是操作系统执行任务的基本单位,处理 ...

  8. Thread的start()和join()方法

    start: 用start方法来启动线程,真正实现了多线程运行,这时无需等待run方法体代码执行完毕而直接继续执行下面的代码.通过调用Thread类的start()方法来启动一个线程,这时此线程处于就 ...

  9. JAVA多线程中join()方法的详细分析

    虽然关于讨论线程join()方法的博客已经非常极其特别多了,但是前几天我有一个困惑却没有能够得到详细解释,就是当系统中正在运行多个线程时,join()到底是暂停了哪些线程,大部分博客给的例子看起来都像 ...

  10. java线程 yield_Java线程中yield与join方法的区别

    长期以来,多线程问题颇为受到面试官的青睐.虽然我个人认为我们当中很少有人能真正获得机会开发复杂的多线程应用(在过去的七年中,我得到了一个机会),但是理解多线程对增加你的信心很有用.之前,我讨论了一个w ...

最新文章

  1. Unsupervised Feature Selection in Signed Social Networks 阅读笔记
  2. 重启asp.net 命令
  3. CSP认证202012-2 期末预测之最佳阈值[C++题解]:遍历、前缀和
  4. 吴恩达:我们说人工智能时,实际在说些什么?
  5. C#异步批量下载文件
  6. mysql update中使用subquery
  7. lz98n外接电源注意问题
  8. Docker Installation : Docker 中安装并启动 Kong
  9. openjudge #输出一个整数序列中与指定数字相同的数的个数。
  10. 网页模板素材|解救不会编程的UI设计师网页设计者!
  11. 冒泡排序、选择排序、插入排序
  12. flask框架_Flask框架的入门:Hello world
  13. 为什么被喷的总是产品经理?
  14. 花了一天的时间给粉丝做了一个小米官网(高仿)
  15. POJ 3253.Fence Repair
  16. 两列数据对比找不同,并且高亮数据不同的单元格
  17. 曾被网友疯狂恶搞的「蚂蚁呀嘿」项目开源上过GitHub热榜
  18. 巨型机是一种什么的超级计算机,把计算机分为巨型机、大中型机按照什么分的...
  19. 2022年京东NLP实习面试题7道
  20. 华为“天才少年”稚晖君被曝离职!两年前加入年薪百万起步的天才少年计划!...

热门文章

  1. C语言经典题目:有5个人坐在一起,问他们分别多少岁?
  2. Tuscany SCA V1.0中的扩展机制和启动过程中的扩展点[11月29日更新]
  3. 不复制项目,idea中同一个项目同时启动多个端口进行访问
  4. CTF隐写(stegsolve)
  5. 神经网络四:Softmax以及与Sigmoid的关系
  6. 【Rust 日报】2023-1-19 Lars Bergstrom当选为Rust基金会董事会主席
  7. 网上的测量工具-在线直尺
  8. 学C语言中输入输出函数,一篇就够了
  9. 编程资料 -C# 多线程 1
  10. 阿里高级外包你待得住吗?