2019独角兽企业重金招聘Python工程师标准>>>

1.join(long)方法的源码

首先看join()源码:

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

从源码中可以看出,join()直接调用了join(long)方法,join(long)源码如下:

 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;}}}

通过阅读源码可以看出,是通过不断轮询的方式去观察线程是否还是活动线程

join(0)是不断的询问线程的状态,直到线程销毁join()方法才会结束。

当millis>0时,不在是wait(0),而是wait(delay),delay是还剩余的millis时间。有人会问第一次wait(delay)后不就已经经过这millis的时间,为什么还会有while执行多次wait(delay)呢?因为这里不仅要考虑wait在delay时间后被唤醒,还要考虑到在delay时间内,被notify唤醒,唤醒后还没有执行到millis的时间,因此要多次调用wait(delay)方法。

2.比较join(long) 与 sleep(long),join方法后语句提前执行问题

join方法底层调用的是wait方法,执行到wait方法可以释放锁,而sleep方法不释放锁

具体细节通过案例来讲解:

首先定义两个线程类:MyThreadA,MyThreadB,其中为了保证两个线程可以同步执行,在MyThreadA中添加一个MyThreadB的实例变量,具体代码如下:

package com.feng.example;public class MyThreadB extends Thread {@Overridesynchronized public void run() {try {System.out.println("begin B thread, ThreadName="+Thread.currentThread().getName()+"==="+System.currentTimeMillis());Thread.sleep(5000);System.out.println("end B thread, ThreadName="+Thread.currentThread().getName()+"==="+System.currentTimeMillis());} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}
package com.feng.example;public class MyThreadA extends Thread {private Thread b;public MyThreadA(Thread b){this.b = b;}@Overridepublic void run() {try {synchronized(b){//只是为了能够和线程b同步System.out.println("begin A thread, ThreadName="+Thread.currentThread().getName()+"==="+System.currentTimeMillis());Thread.sleep(5000);System.out.println("end A thread, ThreadName="+Thread.currentThread().getName()+"==="+System.currentTimeMillis());}} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}
}

测试类如下:

package com.feng.example;public class ThreadTest {/*** @param args*/public static void main(String[] args) {try {Thread b = new MyThreadB();Thread a = new MyThreadA(b);a.start();b.start();b.join(2000);System.out.println("main end"+"==="+System.currentTimeMillis());} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}
}

这个案例的结果并不是唯一的。首先看第一种输出情况

begin A thread, ThreadName=Thread-1===1450080738885
end A thread, ThreadName=Thread-1===1450080743886
begin B thread, ThreadName=Thread-0===1450080743886
end B thread, ThreadName=Thread-0===1450080748886
main end===1450080748886

分析:线程a,b, b.join(2000),三者所执行的操作都是以线程实例b作为锁对象的,也就是说三者需要同步执行。一般来说main函数中的代码执行要比启动线程的代码执行要快。(这不是重点),运行结果解释如下:

(1)三者中b.join(2000)首先抢到b的锁,然后代码执行到wait(delay)释放锁对象(去看上面的join(long)源码)

(2)线程a,b争抢锁,线程a获得锁对象,执行synchronized(b){}语句块,执行过程中Thread.sleep(5000)不释放锁,直到执行完成

(3)线程b与b.join(2000)方法争抢锁,线程b抢到锁对象,执行run方法,直到执行完

(4)b.join(2000)获得锁,发现线程b已经销毁,join方法执行完毕。

(5)打印main end语句。

上述解释中join争抢锁可以是在a执行完之后,不影响输出结果。

再看第二种运行情况:

begin A thread, ThreadName=Thread-1===1450082014528
end A thread, ThreadName=Thread-1===1450082019529
main end===1450082019529
begin B thread, ThreadName=Thread-0===1450082019529
end B thread, ThreadName=Thread-0===1450082024530

解释如下:

(1)三者中b.join(2000)首先抢到b的锁,然后代码执行到wait(delay)释放锁对象(去看上面的join(long)源码)

(2)线程a,b争抢锁,线程a获得锁对象,执行synchronized(b){}语句块,执行过程中Thread.sleep(5000)不释放锁,直到执行完成

(3)线程b与b.join(2000)方法争抢锁,b.join抢到锁,发现已经超过2s,因此join方法执行完成,输出main end,释放锁

(4)线程b获得锁,执行run方法

还有一只输出可能,这种可能不好演示,直接给出结果:

begin A thread, ThreadName=Thread-1===1450082014528
end A thread, ThreadName=Thread-1===1450082019529
begin B thread, ThreadName=Thread-0===1450082019529
main end===1450082019529
end B thread, ThreadName=Thread-0===1450082024530

解释如下:

(1)三者中b.join(2000)首先抢到b的锁,然后代码执行到wait(delay)释放锁对象(去看上面的join(long)源码)

(2)线程a,b争抢锁,线程a获得锁对象,执行synchronized(b){}语句块,执行过程中Thread.sleep(5000)不释放锁,直到执行完成

(3)线程b与b.join(2000)方法争抢锁,b.join抢到锁,发现已经超过2s,因此join方法执行完成,释放锁

(4)线程b获得锁,在主线程的输出语句运行之前执行了线程b的run方法,这里main线程与b线程属于异步执行。

从上例中可以看出join与sleep的不同,调用sleep时只是单纯的阻塞,并且不会释放锁。上例同时解释了join方法后语句提前执行的情况。

重点理解join方法获取锁,执行到wait方法直接释放锁的问题。

3.存在的困惑

主线程调用b.join方法,在join方法中是是让线程b执行wait方法,明明是线程b等待,又如何达到让主线程等待的功能呢?

b.wait到底wait的是什么,线程b为什么还能执行????

自我解释:

首先b.wait(),b只是代表一个锁,等待的是执行b.wait()的线程。

join和wait一样,哪个线程执行的此操作,等待的就是哪个线程,和调用者没有关系,调用者只是一个锁对象而已。

转载于:https://my.oschina.net/u/2309504/blog/544220

join(long)与sleep(long)的区别相关推荐

  1. Oracle的left join中on和where的区别

    Oracle的left join中on和where的区别 数据库在通过连接两张或多张表来返回记录时,都会生成一张中间的临时表,然后再将这张临时表返回给用户. 在使用left jion时,on和wher ...

  2. Java-线程中sleep()、wait()和notify()和notifyAll()、suspend和resume()、yield()、join()、interrupt()的用法和区别

    Java线程中sleep().wait()和notify()和notifyAll().suspend和resume().yield().join().interrupt()的用法和区别 从操作系统的角 ...

  3. hive join on 条件 与 where 条件区别

    hive join on 条件 与 where 条件区别 1. select * from a left join b on a.id = b.id and a.dt=20181115;2. sele ...

  4. 深入Oracle的left join中on和where的区别详解

    今天遇到一个求某月所有天数的统计结果,如果某日的结果是0也需要显示出来,即: 日期                  交易次数   交易金额 2009-4-01           1         ...

  5. 【mysql】left join on and 和 where的区别

    left join on and SELECT a.order_id ,b.id FROM way_order a LEFT JOIN way_order_product b ON a.order_i ...

  6. hive 的 left semi join 讲解与left jion的区别

    一:介绍 他们都是 hive join 方式的一种,join on 属于 common join(shuffle join/reduce join), 而 left semi join 则属于 map ...

  7. Python教程:threading中join与setDaemon的用法及区别讲解

    Python多线程编程时经常会用到join()和setDaemon()方法,基本用法如下: join([time]): 等待至线程中止.这阻塞调用线程直至线程的join() 方法被调用中止-正常退出或 ...

  8. Thread.join(), CountDownLatch、CyclicBarrier和 Semaphore区别,联系及应用

    在java 1.5中,提供了一些非常有用的辅助类来帮助我们进行并发编程,比如CountDownLatch,CyclicBarrier和Semaphore,今天我们就来学习一下这三个辅助类的用法, 由于 ...

  9. Java线程中sleep()、wait()和notify()、suspend()和resume()、yield()、join()、interupt()的用法和区别

    从操作系统的角度讲,os会维护一个ready queue(就绪的线程对列).并在某一时刻CPU只为ready queue中位于队列头部的线程服务.但是当前正在被服务的线程可能觉得cpu的服务质量不够好 ...

最新文章

  1. pythonpandas读取csv和另外一个csv进行比较_Python Pandas:比较一个列中类似值的两个csv(dataframe)的行,并返回相似的行(列)的内容...
  2. SSI——服务器端嵌入
  3. [zz]How to sign .EXE, .DLL and .CAB files?
  4. 如何导入外部Git仓库到中国源代码托管平台(Git@OSC)
  5. 在一个机器上创建多个独立Firefox运行环境
  6. 一年级下册健康教育教案
  7. 哈工大密码学实验(CA证书认证系统)
  8. 【1+X】软件测试用例概述
  9. JSP——编写一个简单的JSP页面,显示英文字母表
  10. python实现qq自动点赞_python实现自动点赞
  11. Windows与linux开发板文件传输和固件更新工具——tftpd32软件操作说明
  12. c语言达内月考试题,达内C培训第一次月考〔附答案〕.doc
  13. 扛住时间,不负自我,37岁自学计算机语言-Python的后果
  14. 阿里巴巴python招聘_作为应届生,我在阿里巴巴的成功面试经历!
  15. mysql中辅导方式选择_MYSQL中如何选择合适的数据类型
  16. 切勿忽视晶振的选型设计!
  17. 嘚吧嘚java的发展历史
  18. 软件开发中产品与项目区别
  19. 智能车图像部分——摄像头寻迹
  20. 《写作的诞生》读后感

热门文章

  1. KB奇遇记(9):艰难的上线
  2. windows Server 2008+iis 7.5 部署应用程序
  3. java encode乱码_java 中文乱码问题的解决
  4. 计算机网络管理员高级操作技能考核试卷,高级计算机维修工操作技能考核试卷...
  5. python装饰器class_Python装饰器dataclass详解
  6. token怎么获取 php,如何用php获取某个页面中的input的csrf_token?
  7. mysql3308_mysql 多服务器范例
  8. python pandas 读取数据库_数据分析-pandas从数据库读取数据
  9. ppt转html5 带动画_天府味道 小吃龙门阵____糖饼糖画 难以忘怀的童年趣味
  10. css3 fieldset,CSS3 fieldset/input 音乐均衡器/音效调节器