最近在看Java多线程的同步工具,正好看到了CountDownLatch和Join的区别,看到main线程里join的调用,写了几个例子,帮助
理解join的执行。
这个是执行类,执行的是sleep3秒
package top.huster.thread; import java.util.concurrent.TimeUnit; public class SleepThread implements Runnable { private String name; public SleepThread(String name) { this.name = name; } public void run() { Thread.currentThread().setName(name); System.out.println("start to sleep " + Thread.currentThread().getName()); try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { } System.out.println("end Sleep " + Thread.currentThread().getName()); } }
case1 : 以下程序的输出结果
package top.huster.thread; public class TestThread { public static void main(String[] args) { Thread thread = new Thread(new SleepThread("thread")); try { thread.start(); thread.join(); } catch (InterruptedException e) { } System.out.println("main thread end " + Thread.currentThread().getName()); } }
这个结果比较明显,无论怎么调用,输出结果始终是
start to sleep thread
end Sleep thread
main thread end main
因为main线程会等待join线程的结束,才会继续往下执行。
case2:
package top.huster.thread; public class TestThread2 { public static void main(String[] args) { Thread thread1 = new Thread(new SleepThread("thread1")); Thread thread2 = new Thread(new SleepThread("thread2")); Thread thread3 = new Thread(new SleepThread("thread3")); try { thread1.start(); thread2.start(); thread3.start(); thread1.join(); System.out.println("waiting for thread1"); thread2.join(); System.out.println("waiting for thread2"); thread3.join(); System.out.println("waiting for thread3"); } catch (InterruptedException e) { } System.out.println("main thread end " + Thread.currentThread().getName()); } }
这个执行的结果大概是,无论thread1,thread2,thread3那个先start那个先end,顺序一定是3个Thread的全部end之后,在执行打印waiting那几行,并且waiting的顺序是1,2,3
这里可能有点理解的奇怪,当调用了thread1.join不应该阻塞住,然后等thread1执行完毕,再执行打印waiting,再执行thread2.join的代码吗?
start to sleep thread2
start to sleep thread3
start to sleep thread1
end Sleep thread1
end Sleep thread2
end Sleep thread3
waiting for thread1
waiting for thread2
waiting for thread3
main thread end main
分析上面的结果,可能是thread1.join之后,main被阻塞,等thread1.join执行完毕,thread2,thread3正好执行完毕,这个时候join代码就失效了,然后执行了main里面打印的waiting。
为了验证这个问题,我们修改下
package top.huster.thread; import java.util.concurrent.TimeUnit; public class SleepThread implements Runnable { private String name; private int sleep; public SleepThread(String name, int sleep) { this.name = name; this.sleep = sleep; } public void run() { Thread.currentThread().setName(name); System.out.println("start to sleep " + Thread.currentThread().getName()); try { TimeUnit.SECONDS.sleep(sleep); } catch (InterruptedException e) { } System.out.println("end Sleep " + Thread.currentThread().getName()); } }
package top.huster.thread; public class TestThread2 { public static void main(String[] args) { Thread thread1 = new Thread(new SleepThread("thread1", 1)); Thread thread2 = new Thread(new SleepThread("thread2", 10)); Thread thread3 = new Thread(new SleepThread("thread3", 15)); try { thread1.start(); thread2.start(); thread3.start(); thread1.join(); System.out.println("waiting for thread1"); thread2.join(); System.out.println("waiting for thread2"); thread3.join(); System.out.println("waiting for thread3"); } catch (InterruptedException e) { } System.out.println("main thread end " + Thread.currentThread().getName()); } } 我们让第一个线程sleep 1 秒,这样在thread1结束的时候,可以让main线程继续执行,也就是打印waiting for thread1, 这个时候遇到了thread2.join,继续阻塞直到thread2结束,打印waiting for thread2, 在遇到thread3.join继续阻塞,直到thread3 结束,再次回到main线程,所以打印结果是 start to sleep thread1 start to sleep thread3 start to sleep thread2 end Sleep thread1 waiting for thread1 end Sleep thread2 waiting for thread2 end Sleep thread3 waiting for thread3 main thread end main 如果改成这样将他们的时间都改成1s, 然后去掉thread1.join,也就是不用等待thread1结束。
public static void main(String[] args) { Thread thread1 = new Thread(new SleepThread("thread1", 1)); Thread thread2 = new Thread(new SleepThread("thread2", 1)); Thread thread3 = new Thread(new SleepThread("thread3", 1)); try { thread1.start(); thread2.start(); thread3.start(); //thread1.join(); System.out.println("waiting for thread1"); thread2.join(); System.out.println("waiting for thread2"); thread3.join(); System.out.println("waiting for thread3"); } catch (InterruptedException e) { } System.out.println("main thread end " + Thread.currentThread().getName()); }
返回结果如下
start to sleep thread1
start to sleep thread2
start to sleep thread3
waiting for thread1
end Sleep thread1
end Sleep thread2
end Sleep thread3
waiting for thread2
waiting for thread3
main thread end main
waiting for thread1真的跑到了thread1结束之前(不稳定),然后还有个原则是waiting for thread2一定在thread2结束之后,waiting for thread3一定在thread3结束之后。