首先,我们要明白,程序都是主线程优先执行(优先获取锁),然后才是从线程,而从线程和从线程是对等的,则会出现交替执行情况,程序是不可控的。
其次,join方法的意义有2个:(1)使用该方法可以让主线程将锁让给从线程(因为join方法源码是一个synchronized方法),并指定从线程执行的总时间;(2)可以将几个并发的从线程进行合并,变成一窜串行的代码,从而使得运行结果在预期范围,变成可控。
观察下面三段代码结果有何不同:
//第一段
/*
* join因为是一个synchronized方法(悲观锁,独占锁,阻塞同步),主线程立马释放锁,从线程将获取锁。
* 指定join执行时间:意思是在规定时间内从线程不管是否全部执行完毕,时间到达,都将锁立即释放,并归还给主线程。
*/
public class TestJoin implements Runnable {
public static void main(String[] sure) throws InterruptedException {
long start = System.currentTimeMillis();
Thread t = new Thread(new TestJoin());
t.start();
// //没有join方法:主线程执行完毕,再执行从线程
//t.join(); //主线程立马将执行锁给从线程T,从线程T全部执行完毕再归还执行锁给主线程
t.join(2000);//主线程立马将执行锁给从线程T,从线程T执行2000毫秒后立马归还执行锁给主线程
System.out.println(System.currentTimeMillis()-start);//打印出时间间隔
System.out.println("Main finished");//打印主线程结束
}
@Override
public void run() {
//synchronized (currentThread()) {
for (int i = 1; i <= 5; i++) {
try {
Thread.sleep(1000);//睡眠5秒,循环是为了方便输出信息
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("睡眠" + i);
}
System.out.println("TestJoin finished");//t线程结束
//}
}
}
//第二段
import static java.lang.Thread.currentThread;
import static java.lang.Thread.sleep;
public class TestJoin3 {
public static void main(String[] args) throws InterruptedException {
//...
Thread t1 = new Thread(() -> {
try {
Thread.sleep(3000);
System.out.println("--- 休眠 3 秒");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
t1.start();
try {
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("--- work thread continue");
}
}
//第三段
import static java.lang.Thread.currentThread;
import static java.lang.Thread.sleep;
public class TestJoin2 {
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(new JoinThread());;
Thread thread2 = new Thread(new JoinThread());
thread1.start();
thread1.join();
thread2.start();
}
static class JoinThread implements Runnable {
@Override
public void run() {
for(int i=0; i<3; i++) {
try {
System.out.println(Thread.currentThread().getName());
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}