欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

join的简单总结

程序员文章站 2023-04-08 10:11:47
BAT面试题:现在有T1、T2、T3三个线程,你怎样保证T2在T1执行完后执行,T3在T2执行完后执行? 这个线程问题通常会在第一轮或电话面试阶段被问到,目的是检测你对”join”方法是否熟悉。这个多线程问题比较简单,可以用join方法实现。 一、作用 Thread类中的join方法的主要作用就是同 ......

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线程,从而达到同步的目的。