join方法的扇入探究
Posted clover-forever
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了join方法的扇入探究相关的知识,希望对你有一定的参考价值。
join的探究
首先明确join的作用:t.join()方法只会使主线程(或者说是t.join()的线程)进入等待池并等待t线程执行完毕后才被唤醒。但是并不会影响同一时刻其他处在运行状态的线程。
下面来分析一下有无join()的差别:
无join时:
// 资源类
package com.join;
public class ThreadTest extends Thread{
private String name;
public ThreadTest(String name) {
this.name = name;
}
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(name+"--->"+i);
}
}
}
// 测试方法
package com.join;
public class Demo {
public static void main(String[] args) throws InterruptedException {
ThreadTest t1 = new ThreadTest("A");
ThreadTest t2 = new ThreadTest("B");
t1.start();
System.out.println("t1111111111111111111111111111111");
t2.start();
System.out.println("t2222222222222222222222222222222");
}
}
运行结果
t1111111111111111111111111111111
A--->0
A--->1
A--->2
A--->3
A--->4
t2222222222222222222222222222222
B--->0
B--->1
B--->2
B--->3
B--->4
可以看出:t1,t2线程以及main执行时随机无序的。
但是加入join()时候:
package com.join;
public class Demo {
public static void main(String[] args) throws InterruptedException {
ThreadTest t1 = new ThreadTest("A");
ThreadTest t2 = new ThreadTest("B");
t1.start();
t1.join();
System.out.println("t1111111111111111111111111111111");
t2.start();
System.out.println("t2222222222222222222222222222222");
}
}
可以看出t2线程在线程t1之后执行:
package com.join;
public class Demo {
public static void main(String[] args) throws InterruptedException {
ThreadTest t1 = new ThreadTest("A");
ThreadTest t2 = new ThreadTest("B");
t1.start();
System.out.println("t1111111111111111111111111111111");
t2.start();
t1.join();
System.out.println("t2222222222222222222222222222222");
}
}
t1111111111111111111111111111111
A--->0
A--->1
A--->2
A--->3
B--->0
B--->1
B--->2
B--->3
B--->4
A--->4
t2222222222222222222222222222222
这种情况可以看出来:t1与t2仍然交替打印,随机无序的。
为了深入理解,我们看一下join()的源码:
public final void join() throws InterruptedException {
join(0); //join()等同于join(0)
}
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
// 如果小于0抛出异常
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
// 如果还活着,就调用wait
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
// 如果还活着,还是会调用wait方法
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
从源码可以看出,join()方法的底层是用wait()方法实现的,可以看出,join方法是一个同步方法,当主线程调用t1.join()的时候,主线程获得了t1对象的锁,随后进入方法,调用了t1对象的wait方法,使主线程进入了t1对象的等待池,此时,t1线程还在执行,并且后面的t2.start()还没有执行,因此,t2线程还没有开始。等到t1线程执行完毕之后,主线程继续执行,执行了t2.start(),t2线程才会执行。
因此,可以得出结论,t.join()方法只会使主线程进入等待池并等待t线程执行完毕后才会被唤醒,同时并不影响同一时刻其他正在执行的线程。
注意:join源码中,只会调用wait方法,并没有在结束时调用notify,这是因为线程在die的时候会自动调用自身的notifyAll方法,来释放所有的资源和锁。
参考文章链接:
https://blog.csdn.net/u013425438/article/details/80205693
以上是关于join方法的扇入探究的主要内容,如果未能解决你的问题,请参考以下文章
SQL 中 left join 的底层原理(各种JOIN的复杂度探究)