thread.join()方法的作用:保证线程的执行结果的可见性。原理是通过阻塞主线程实现的。
代码Demo如下:
public class ThreadJoinDemo {
public static volatile boolean flag = false;
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try {
//线程睡眠500毫秒。确保其他线程先执行完
TimeUnit.MILLISECONDS.sleep(500);
flag = true;
System.out.println("线程t1执行完了");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
if (flag){
System.out.println("flag 为 true了");
}else {
System.out.println("flag 为 false了");
}
}
});
t1.start();
t2.start();
System.out.println("主线程执行完了");
}
}
说明:
1. 线程t1的run()方法的作用是将共享变量flag修改为true。但因为睡眠了500毫秒,线程t2和主线程先执行完了,使得线程t1对flag的修改结果对其他线程不可见。
3. 线程t2的run()方法的作用是根据共享变量的值来输出不同的值。
执行结果:
解释图发生上图结果的情况(假设单cpu):
总结:以上情况线程t1对flag的修改结果对线程t2不可见。
通过thread.join()实现线程执行结果的可见性。
public class ThreadJoinDemo {
public static volatile boolean flag = false;
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try {
//线程睡眠500毫秒。
TimeUnit.MILLISECONDS.sleep(500);
flag = true;
System.out.println("线程t1执行完了");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
if (flag){
System.out.println("flag 为 true了");
}else {
System.out.println("flag 为 false了");
}
}
});
t1.start();
//是通过阻塞主线程实现t1线程执行结果可见,主线程被阻塞在这里,
//t2.start()代码就没有办法执行,t2线程就还没启动,直到t1线程执行完毕,才继续主线程往下走。
t1.join(); //这里改变了
t2.start();
System.out.println("主线程执行完了");
}
}
说明:
1. t1.join()方法,保证了t1线程执行结果对其他线程的可见性,是通过阻塞主线程实现的。
保证t1线程执行完毕才继续执行主线程。
2. 底层是通过wait/notify机制实现的,阻塞主线程,知道t1线程执行完毕才通过notify唤醒。
执行结果:
结果解释图(假设单cpu):
thread.join()方法还有两个重载方法:
/**
* 参数millis:毫秒数,指定join阻塞主线程的超时时间,如果超过时间后该线程还没执行完毕,就不阻塞主线程了
**/
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) {
//如果millis为0,则阻塞无限期直到线程执行完毕。与thread.join()效果一样。
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
//要么超时,要么线程执行完毕
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
/**
* millis:毫秒
* nanos:纳秒
*/
public final synchronized void join(long millis, int nanos)
throws InterruptedException {
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}
//nanos 符合这个情况,毫秒数加一。
if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
millis++;
}
//thread.join(0,0)与thread.join()效果一样。
join(millis);
}
public final void join() throws InterruptedException {
//就是调用thread.join(int millis)方法,参数传递0。
join(0);
}