您的位置:首页 > 其它

Thread的join()方法理解

2018-02-02 21:36 232 查看
Thread的join()方法的官方文档给出的解释是:等待该线程终止。我们可以参考一下代码

public class Student1 extends Thread {
@Override
public void run(){
for(int i=1;i<10;i++){
System.out.println(getName()+"-->"+i);
}
}
}
public class ReadMain {
public static void main(String[] args) throws InterruptedException{
Student1 s1 = new Student1();
s1.setName("线程1"); //为线程命名
s1.start();
//s1.join();
for(int i=0;i<10;i++){
System.out.println("main-->"+i);
}
}
}我们在没有join()方法之前,执行结果:
main-->0
线程1-->1
main-->1
线程1-->2
main-->2
线程1-->3
main-->3
线程1-->4
线程1-->5
main-->4
线程1-->6
main-->5
线程1-->7
main-->6
线程1-->8
main-->7
线程1-->9
main-->8
main-->9加上s1.join()方法后,结果如下:
线程1-->1
线程1-->2
线程1-->3
线程1-->4
线程1-->5
线程1-->6
线程1-->7
线程1-->8
线程1-->9
main-->0
main-->1
main-->2
main-->3
main-->4
main-->5
main-->6
main-->7
main-->8
main-->9可以看出线程1先执行完后,再是主线程main执行,join()方法的官方解释是:等待该线程终止。根据上面的结果 我们可以推测是让调用s1.join()的线程(这里既是主线程main)等待被调用线程(这里既是线程1)执行完后再执行调用s1.join()的 线程(main线程),即将调用线程(main线程)阻塞。
这里只有两个线程,我们现在在添加两个线程线程2和线程3,观察输出结果:

线程1-->1
线程3--->0
线程2:-->1
线程3--->1
线程1-->2
线程3--->2
线程2:-->2
线程3--->3
线程1-->3
线程3--->4
线程2:-->3
线程3--->5
线程1-->4
线程3--->6
线程2:-->4
线程3--->7
线程1-->5
线程3--->8
线程2:-->5
线程3--->9
线程1-->6
线程1-->7
线程1-->8
线程1-->9
线程2:-->6
线程2:-->7
main-->0
线程2:-->8
main-->1
线程2:-->9
main-->2
main-->3
main-->4
main-->5
main-->6
main-->7
main-->8
main-->9我们根据上面的结果可以得出其执行的顺序:
主线程main先执行到s1.start()之前,此时虽然有创建的线程,但没有启动,所以参与到抢夺cpu的只有主线程一个,所以为单线程,当主线程main执行到s1.start(),启动s1线程(此时抢夺cpu的线程有两个为:s1线程和主线程main),此时cpu可能执行s1线程也可能执行主线程main,当主线程抢到cpu,主线程执行到s3.start(),此时有三个线程参与到抢夺cpu的行动中(s1线程,s3线程,主线程main),他们谁抢到cpu就执行谁的线程中的指令,当主线程抢到cpu,主线程main执行s2.start()时,此时有四个线程参与到抢夺cpu的行动中(s1线程,s3线程,主线程main,s2线程),谁抢到cpu就执行谁的指令,当主线程main抢到cpu后,执行到s1.join(),然后就告诉调用s1.join()的线程(这里为主线程)你要阻塞,直到s1线程执行完后,主线程才可以执行(这里可以理解为主线程才就可以参与到抢夺cpu资源中去了,此时实际有资格抢夺cpu的只有三个线程:s1线程,s2线程,s3线程,这三个线程谁抢到cpu就可以执行谁的指令,此时主线程main处于阻塞状态,不参与抢夺cpu的行动),当s1线程执行完后,s2线程,s3线程和主线程三个中没有执行完的(此时s2线程和s3线程可能执行完,也可能没有执行完,主线程肯定没有执行完
)有参与到抢夺cpu的行动中,谁抢到就执行谁的,直到主线程执行完(此时所有的线程也就执行完了)。我们也可以从了另一个例子验证我们上面的解释。我们只是修改了Student1和ReadMain的代码

public class Student1 extends Thread {
@Override
public void run(){
for(int i=1;i<10;i++){
System.out.println(getName()+"-->"+i);
if(i==5){
Student2 s2 = new Student2();
s2.setName("线程2");
s2.start();
try {
s2.join();
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
}
}
}
public class ReadMain {
public static void main(String[] args) throws InterruptedException{
Student1 s1 = new Student1();
s1.setName("线程1"); //为线程命名
s1.start();
for(int i=0;i<10;i++){
System.out.println("main-->"+i);
}
}
}

main-->0
线程1-->1
main-->1
main-->2
main-->3
main-->4
main-->5
main-->6
线程1-->2
main-->7
线程1-->3
main-->8
线程1-->4
main-->9
线程1-->5
线程2:-->1
线程2:-->2
线程2:-->3
线程2:-->4
线程2:-->5
线程2:-->6
线程2:-->7
线程2:-->8
线程2:-->9
线程1-->6
线程1-->7
线程1-->8
线程1-->9
从上面的输出可以解释执行的顺序:

前面的都一样,当我们执行到s1.start()时,此时有两个线程抢夺cpu(主线程 main和s1线程),当s1抢到cpu,执行其中的for循环,当执行到i==5时,进去if,创建了一个线程s2,并启动了线程2,然后,有三个线程参与抢夺cpu(主线程main,s1线程,s2线程),若s1抢到cpu,则执行到s2.join(),此时调用 s2.join()的线程(s1线程)阻塞,此时有两个线程(s2线程,主线程main)参与到抢夺cpu行动中(s1此时正在被阻塞,无法参与抢夺cpu,只有等到s2线程执行完后,s1线程才可以参与到抢夺cpu中),所以当s2线程执行完后,s1线程才可以和主线程main参与到抢夺cpu行动中(若没有执行完则参与到其中)。

join()这里不带参数意思为一直等下去,无限等待,若加上参数则为调用线程等待的最大时间数,若在此时间内被调用的线程没有执行完,则意味着调用线程可以重新参与到竞争cpu中去。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: