在子线程中通过join()方法指定顺序

通过join()方法使当前线程“阻塞”,等待指定线程执行完毕后继续执行。
举例:在线程thread2中,加上一句thread1.join(),其意义在于,当前线程2运行到此行代码时会进入阻塞状态,直到线程thread1执行完毕后,线程thread2才会继续运行,这就保证了线程thread1与线程thread2的运行顺序。

  1. public class ThreadJoinDemo {
  2. public static void main(String[] args) throws InterruptedException {
  3. final Thread thread1 = new Thread(new Runnable() {
  4. @Override
  5. public void run() {
  6. System.out.println("打开冰箱!");
  7. }
  8. });
  9. final Thread thread2 = new Thread(new Runnable() {
  10. @Override
  11. public void run() {
  12. try {
  13. thread1.join();
  14. } catch (InterruptedException e) {
  15. e.printStackTrace();
  16. }
  17. System.out.println("拿出一瓶牛奶!");
  18. }
  19. });
  20. final Thread thread3 = new Thread(new Runnable() {
  21. @Override
  22. public void run() {
  23. try {
  24. thread2.join();
  25. } catch (InterruptedException e) {
  26. e.printStackTrace();
  27. }
  28. System.out.println("关上冰箱!");
  29. }
  30. });
  31. //下面三行代码顺序可随意调整,程序运行结果不受影响,因为在子线程中通过“join()方法”已经指定了运行顺序。
  32. thread3.start();
  33. thread2.start();
  34. thread1.start();
  35. }
  36. }

运行结果:

  1. 打开冰箱!
  2. 拿出一瓶牛奶!
  3. 关上冰箱!

在主线程中通过join()方法指定顺序

简单说一下子线程与主线程的区别,子线程指的是发生在Thread内部的代码,主线程指的是发生在main函数中的代码,可以在main函数中通过join()方法让主线程阻塞等待以达到指定顺序执行的目的。

  1. public class ThreadMainJoinDemo {
  2. public static void main(String[] args) throws InterruptedException {
  3. final Thread thread1 = new Thread(new Runnable() {
  4. @Override
  5. public void run() {
  6. System.out.println("打开冰箱!");
  7. }
  8. });
  9. final Thread thread2 = new Thread(new Runnable() {
  10. @Override
  11. public void run() {
  12. System.out.println("拿出一瓶牛奶!");
  13. }
  14. });
  15. final Thread thread3 = new Thread(new Runnable() {
  16. @Override
  17. public void run() {
  18. System.out.println("关上冰箱!");
  19. }
  20. });
  21. //join()方法使当前线程“阻塞”,等待指定线程执行完毕后继续执行。
  22. //使主线程等待,thread1执行完毕后,主线程继续执行
  23. thread1.start();
  24. thread1.join();
  25. thread2.start();
  26. thread2.join();
  27. thread3.start();
  28. }
  29. }

输出结果:

  1. 打开冰箱!
  2. 拿出一瓶牛奶!
  3. 关上冰箱!

通过倒数计时器CountDownLatch实现

CountDownLatch通过计数器提供了更灵活的控制,只要检测到计数器为0当前线程就可以往下执行而不用管相应的thread是否执行完毕。

  1. CountDownLatch(int count); //构造方法,创建一个值为count 的计数器。
  2. await();//阻塞当前线程,将当前线程加入阻塞队列。
  3. await(long timeout, TimeUnit unit);//在timeout的时间之内阻塞当前线程,时间一过则当前线程可以执行,
  4. countDown();//对计数器进行递减1操作,当计数器递减至0时,当前线程会去唤醒阻塞队列里的所有线程。
  1. public class ThreadCountDownLatchDemo {
  2. private static CountDownLatch countDownLatch1 = new CountDownLatch(1);
  3. private static CountDownLatch countDownLatch2 = new CountDownLatch(1);
  4. public static void main(String[] args) {
  5. final Thread thread1 = new Thread(new Runnable() {
  6. @Override
  7. public void run() {
  8. System.out.println("打开冰箱!");
  9. countDownLatch1.countDown();
  10. }
  11. });
  12. final Thread thread2 = new Thread(new Runnable() {
  13. @Override
  14. public void run() {
  15. try {
  16. countDownLatch1.await();
  17. System.out.println("拿出一瓶牛奶!");
  18. countDownLatch2.countDown();
  19. } catch (InterruptedException e) {
  20. e.printStackTrace();
  21. }
  22. }
  23. });
  24. final Thread thread3 = new Thread(new Runnable() {
  25. @Override
  26. public void run() {
  27. try {
  28. countDownLatch2.await();
  29. System.out.println("关上冰箱!");
  30. } catch (InterruptedException e) {
  31. e.printStackTrace();
  32. }
  33. }
  34. });
  35. //下面三行代码顺序可随意调整,程序运行结果不受影响
  36. thread3.start();
  37. thread1.start();
  38. thread2.start();
  39. }
  40. }

输出结果:

  1. 打开冰箱!
  2. 拿出一瓶牛奶!
  3. 关上冰箱!

通过创建单一化线程池newSingleThreadExecutor()实现

单线程化线程池(newSingleThreadExecutor)的优点,串行执行所有任务。

  1. public class ThreadPoolDemo {
  2. static ExecutorService executorService = Executors.newSingleThreadExecutor();
  3. public static void main(String[] args) {
  4. final Thread thread1 = new Thread(new Runnable() {
  5. @Override
  6. public void run() {
  7. System.out.println("打开冰箱!");
  8. }
  9. });
  10. final Thread thread2 =new Thread(new Runnable() {
  11. @Override
  12. public void run() {
  13. System.out.println("拿出一瓶牛奶!");
  14. }
  15. });
  16. final Thread thread3 = new Thread(new Runnable() {
  17. @Override
  18. public void run() {
  19. System.out.println("关上冰箱!");
  20. }
  21. });
  22. executorService.submit(thread1);
  23. executorService.submit(thread2);
  24. executorService.submit(thread3);
  25. executorService.shutdown(); //使用完毕记得关闭线程池
  26. }
  27. }

输出结果:

  1. 打开冰箱!
  2. 拿出一瓶牛奶!
  3. 关上冰箱!

按顺序打印