在 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. 使用 ExecutorService
和 Future
- 通过
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()
:简单易用,适合线程数量较少的场景。ExecutorService
和Future
:适合任务提交和结果获取的场景。CountDownLatch
:适合一个线程等待多个线程完成的场景。CyclicBarrier
:适合多个线程同时开始执行的场景。Semaphore
:适合通过信号量控制线程执行顺序的场景。
根据具体需求选择合适的工具,可以有效控制多个线程的执行顺序。
THE END
暂无评论内容