面试题:如何在 Java 中控制多个线程的执行顺序?

在 Java 中,线程的执行顺序是由操作系统的线程调度器决定的,通常情况下是无法直接控制的。然而,在某些场景下,我们需要确保多个线程按照特定的顺序执行。以下是几种常见的控制线程执行顺序的方法:


1. 使用 join() 方法

  • join() 方法可以让当前线程等待另一个线程执行完毕后再继续执行。
  • 通过调用 thread.join(),可以确保线程 thread 执行完毕后,当前线程才会继续执行。 示例代码:
   public class JoinExample {
       public static void main(String[] args) throws InterruptedException {
           Thread thread1 = new Thread(() -> System.out.println("Thread 1"));
           Thread thread2 = new Thread(() -> System.out.println("Thread 2"));
           Thread thread3 = new Thread(() -> System.out.println("Thread 3"));

           thread1.start();
           thread1.join(); // 等待 thread1 执行完毕

           thread2.start();
           thread2.join(); // 等待 thread2 执行完毕

           thread3.start();
           thread3.join(); // 等待 thread3 执行完毕
       }
   }

输出:

   Thread 1
   Thread 2
   Thread 3

2. 使用 ExecutorServiceFuture

  • 通过 ExecutorService 提交任务,并使用 Future 对象控制任务的执行顺序。
  • Future.get() 方法会阻塞当前线程,直到任务执行完毕。 示例代码:
   import java.util.concurrent.*;

   public class ExecutorServiceExample {
       public static void main(String[] args) throws ExecutionException, InterruptedException {
           ExecutorService executor = Executors.newSingleThreadExecutor();

           Future<?> future1 = executor.submit(() -> System.out.println("Task 1"));
           future1.get(); // 等待 Task 1 执行完毕

           Future<?> future2 = executor.submit(() -> System.out.println("Task 2"));
           future2.get(); // 等待 Task 2 执行完毕

           Future<?> future3 = executor.submit(() -> System.out.println("Task 3"));
           future3.get(); // 等待 Task 3 执行完毕

           executor.shutdown();
       }
   }

输出:

   Task 1
   Task 2
   Task 3

3. 使用 CountDownLatch

  • CountDownLatch 是一个同步工具类,允许一个或多个线程等待其他线程完成操作。
  • 通过 countDown() 方法减少计数器,await() 方法阻塞当前线程,直到计数器为 0。 示例代码:
   import java.util.concurrent.CountDownLatch;

   public class CountDownLatchExample {
       public static void main(String[] args) throws InterruptedException {
           CountDownLatch latch1 = new CountDownLatch(1);
           CountDownLatch latch2 = new CountDownLatch(1);

           Thread thread1 = new Thread(() -> {
               System.out.println("Thread 1");
               latch1.countDown(); // 通知 Thread 2 可以执行
           });

           Thread thread2 = new Thread(() -> {
               try {
                   latch1.await(); // 等待 Thread 1 执行完毕
                   System.out.println("Thread 2");
                   latch2.countDown(); // 通知 Thread 3 可以执行
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           });

           Thread thread3 = new Thread(() -> {
               try {
                   latch2.await(); // 等待 Thread 2 执行完毕
                   System.out.println("Thread 3");
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           });

           thread1.start();
           thread2.start();
           thread3.start();
       }
   }

输出:

   Thread 1
   Thread 2
   Thread 3

4. 使用 CyclicBarrier

  • CyclicBarrier 是一个同步工具类,允许多个线程在某个屏障点等待,直到所有线程都到达屏障点后,再继续执行。
  • 适合需要多个线程同时开始执行的场景。 示例代码:
   import java.util.concurrent.CyclicBarrier;

   public class CyclicBarrierExample {
       public static void main(String[] args) {
           CyclicBarrier barrier = new CyclicBarrier(3, () -> System.out.println("All threads reached the barrier"));

           Thread thread1 = new Thread(() -> {
               try {
                   System.out.println("Thread 1");
                   barrier.await(); // 等待其他线程
               } catch (Exception e) {
                   e.printStackTrace();
               }
           });

           Thread thread2 = new Thread(() -> {
               try {
                   System.out.println("Thread 2");
                   barrier.await(); // 等待其他线程
               } catch (Exception e) {
                   e.printStackTrace();
               }
           });

           Thread thread3 = new Thread(() -> {
               try {
                   System.out.println("Thread 3");
                   barrier.await(); // 等待其他线程
               } catch (Exception e) {
                   e.printStackTrace();
               }
           });

           thread1.start();
           thread2.start();
           thread3.start();
       }
   }

输出:

   Thread 1
   Thread 2
   Thread 3
   All threads reached the barrier

5. 使用 Semaphore

  • Semaphore 是一个计数信号量,用于控制同时访问某个资源的线程数量。
  • 通过 acquire()release() 方法,可以控制线程的执行顺序。 示例代码:
   import java.util.concurrent.Semaphore;

   public class SemaphoreExample {
       public static void main(String[] args) {
           Semaphore semaphore1 = new Semaphore(1);
           Semaphore semaphore2 = new Semaphore(0);
           Semaphore semaphore3 = new Semaphore(0);

           Thread thread1 = new Thread(() -> {
               try {
                   semaphore1.acquire();
                   System.out.println("Thread 1");
                   semaphore2.release();
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           });

           Thread thread2 = new Thread(() -> {
               try {
                   semaphore2.acquire();
                   System.out.println("Thread 2");
                   semaphore3.release();
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           });

           Thread thread3 = new Thread(() -> {
               try {
                   semaphore3.acquire();
                   System.out.println("Thread 3");
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           });

           thread1.start();
           thread2.start();
           thread3.start();
       }
   }

输出:

   Thread 1
   Thread 2
   Thread 3

6. 总结

  • join():简单易用,适合线程数量较少的场景。
  • ExecutorServiceFuture:适合任务提交和结果获取的场景。
  • CountDownLatch:适合一个线程等待多个线程完成的场景。
  • CyclicBarrier:适合多个线程同时开始执行的场景。
  • Semaphore:适合通过信号量控制线程执行顺序的场景。

根据具体需求选择合适的工具,可以有效控制多个线程的执行顺序。

THE END
点赞15 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容