join的简单总结
2018-08-21 05:31:32来源:博客园 阅读 ()
BAT面试题:现在有T1、T2、T3三个线程,你怎样保证T2在T1执行完后执行,T3在T2执行完后执行?
这个线程问题通常会在第一轮或电话面试阶段被问到,目的是检测你对”join”方法是否熟悉。这个多线程问题比较简单,可以用join方法实现。
一、作用
Thread类中的join方法的主要作用就是同步,它可以使得线程之间的并行执行变为串行执行。具体看代码:
1 public class JoinTest { 2 public static void main(String [] args) throws InterruptedException { 3 ThreadJoinTest t1 = new ThreadJoinTest("小明"); 4 ThreadJoinTest t2 = new ThreadJoinTest("小东"); 5 t1.start(); 6 /**join的意思是使得放弃当前线程的执行,并返回对应的线程,例如下面代码的意思就是: 7 程序在main线程中调用t1线程的join方法,则main线程放弃cpu控制权,并返回t1线程继续执行直到线程t1执行完毕 8 所以结果是t1线程执行完后,才到主线程执行,相当于在main线程中同步t1线程,t1执行完了,main线程才有执行的机会 9 */ 10 t1.join(); 11 t2.start(); 12 } 13 14 } 15 class ThreadJoinTest extends Thread{ 16 public ThreadJoinTest(String name){ 17 super(name); 18 } 19 @Override 20 public void run(){ 21 for(int i=0;i<1000;i++){ 22 System.out.println(this.getName() + ":" + i); 23 } 24 } 25 }
上面程序结果是先打印完小明线程,在打印小东线程;
上面注释也大概说明了join方法的作用:在A线程中调用了B线程的join()方法时,表示只有当B线程执行完毕时,A线程才能继续执行。注意,这里调用的join方法是没有传参的,join方法其实也可以传递一个参数给它的,具体看下面的简单例子:
1 public class JoinTest { 2 public static void main(String [] args) throws InterruptedException { 3 ThreadJoinTest t1 = new ThreadJoinTest("小明"); 4 ThreadJoinTest t2 = new ThreadJoinTest("小东"); 5 t1.start(); 6 /**join方法可以传递参数,join(10)表示main线程会等待t1线程10毫秒,10毫秒过去后, 7 * main线程和t1线程之间执行顺序由串行执行变为普通的并行执行 8 */ 9 t1.join(10); 10 t2.start(); 11 } 12 13 } 14 class ThreadJoinTest extends Thread{ 15 public ThreadJoinTest(String name){ 16 super(name); 17 } 18 @Override 19 public void run(){ 20 for(int i=0;i<1000;i++){ 21 System.out.println(this.getName() + ":" + i); 22 } 23 } 24 }
上面代码结果是:程序执行前面10毫秒内打印的都是小明线程,10毫秒后,小明和小东程序交替打印。
所以,join方法中如果传入参数,则表示这样的意思:如果A线程中掉用B线程的join(10),则表示A线程会等待B线程执行10毫秒,10毫秒过后,A、B线程并行执行。需要注意的是,jdk规定,join(0)的意思不是A线程等待B线程0秒,而是A线程等待B线程无限时间,直到B线程执行完毕,即join(0)等价于join()。
二、join与start调用顺序问题
上面的讨论大概知道了join的作用了,那么,如果 join在start前调用,会出现什么后果呢?先看下面的测试结果
1 public class JoinTest { 2 public static void main(String [] args) throws InterruptedException { 3 ThreadJoinTest t1 = new ThreadJoinTest("小明"); 4 ThreadJoinTest t2 = new ThreadJoinTest("小东"); 5 /**join方法可以在start方法前调用时,并不能起到同步的作用 6 */ 7 t1.join(); 8 t1.start(); 9 //Thread.yield(); 10 t2.start(); 11 } 12 13 } 14 class ThreadJoinTest extends Thread{ 15 public ThreadJoinTest(String name){ 16 super(name); 17 } 18 @Override 19 public void run(){ 20 for(int i=0;i<1000;i++){ 21 System.out.println(this.getName() + ":" + i); 22 } 23 } 24 }
上面代码执行结果是:小明和小东线程交替打印。
所以得到以下结论:join方法必须在线程start方法调用之后调用才有意义。这个也很容易理解:如果一个线程都没有start,那它也就无法同步了。
三、join方法实现原理
有了上面的例子,我们大概知道join方法的作用了,那么,join方法实现的原理是什么呢?
其实,join方法是通过调用线程的wait方法来达到同步的目的的。例如,A线程中调用了B线程的join方法,则相当于A线程调用了B线程的wait方法,在调用了B线程的wait方法后,A线程就会进入阻塞状态,具体看下面的源码:
1 public final synchronized void join(long millis) 2 throws InterruptedException { 3 long base = System.currentTimeMillis(); 4 long now = 0; 5 6 if (millis < 0) { 7 throw new IllegalArgumentException("timeout value is negative"); 8 } 9 10 if (millis == 0) { 11 while (isAlive()) { 12 wait(0); 13 } 14 } else { 15 while (isAlive()) { 16 long delay = millis - now; 17 if (delay <= 0) { 18 break; 19 } 20 wait(delay); 21 now = System.currentTimeMillis() - base; 22 } 23 } 24 }
从源码中可以看到:join方法的原理就是调用相应线程的wait方法进行等待操作的,例如A线程中调用了B线程的join方法,则相当于在A线程中调用了B线程的wait方法,当B线程执行完(或者到达等待时间),B线程会自动调用自身的notifyAll方法唤醒A线程,从而达到同步的目的。
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
- Linux简单命令的学习 2020-06-10
- 因为命名被diss无数次。简单聊聊编程最头疼的事情之一:命名 2020-06-10
- 「starter推荐」简单高效Excel 导出工具 2020-06-08
- 总结一些 Java 相关笔试、面试题,万一用上了呢 (=_=) -- 基 2020-06-08
- Mybaties简单实例测试及注意问题 2020-06-07
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash