在面试中出现这道问题,通常是为了考察候选人的以下几个知识点:
join()
、CountDownLatch
、Semaphore
、CyclicBarrier
等,并知道如何在不同场景下应用这些工具。wait()
和 notify()
来协调线程。java.util.concurrent
)中的工具和类,展示其对现代 Java 并发编程的掌握。join()
join()
方法是 Thread
类的一部分,可以让一个线程等待另一个线程完成执行。当你在一个线程 T 上调用 T.join()
时,调用线程将进入等待状态,直到线程 T 完成(即终止)。因此,可以通过在每个线程启动后调用 join()
来实现顺序执行。
示例代码:
Thread t1 = new Thread(() -> {
// 线程 T1 的任务
System.out.println("T1 执行");
});
Thread t2 = new Thread(() -> {
// 线程 T2 的任务
System.out.println("T2 执行");
});
Thread t3 = new Thread(() -> {
// 线程 T3 的任务
System.out.println("T3 执行");
});
t1.start();
try {
t1.join(); // 等待 T1 完成
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
t2.start();
try {
t2.join(); // 等待 T2 完成
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
t3.start();
try {
t3.join(); // 等待 T3 完成
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
CountDownLatch
CountDownLatch
通过一个计数器来实现,初始时,计数器的值由构造函数设置,每次调用 countDown()
方法,计数器的值减 1。当计数器的值变为零时,所有等待在 await()
方法上的线程都将被唤醒,继续执行。
示例代码:
CountDownLatch latch1 = new CountDownLatch(1);
CountDownLatch latch2 = new CountDownLatch(1);
Thread t1 = new Thread(() -> {
// 线程 T1 的任务
System.out.println("T1 执行");
latch1.countDown(); // 完成后递减 latch1
});
Thread t2 = new Thread(() -> {
try {
latch1.await(); // 等待 T1 完成
// 线程 T2 的任务
System.out.println("T2 执行");
latch2.countDown(); // 完成后递减 latch2
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
Thread t3 = new Thread(() -> {
try {
latch2.await(); // 等待 T2 完成
// 线程 T3 的任务
System.out.println("T3 执行");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
t1.start();
t2.start();
t3.start();
Semaphore
Semaphore
通过一个计数器来管理许可,计数器的初始值由构造函数指定,表示可用许可的数量。线程可以通过调用 acquire()
方法请求许可,如果许可可用则授予访问权限,否则线程将阻塞。使用完资源后,线程调用 release()
方法释放许可,从而允许其他阻塞的线程获取许可。
示例代码:
Semaphore semaphore1 = new Semaphore(0);
Semaphore semaphore2 = new Semaphore(0);
Thread t1 = new Thread(() -> {
// 线程 T1 的任务
System.out.println("T1 执行");
semaphore1.release(); // 释放一个许可
});
Thread t2 = new Thread(() -> {
try {
semaphore1.acquire(); // 获取许可,等待 T1 完成
// 线程 T2 的任务
System.out.println("T2 执行");
semaphore2.release(); // 释放一个许可
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
Thread t3 = new Thread(() -> {
try {
semaphore2.acquire(); // 获取许可,等待 T2 完成
// 线程 T3 的任务
System.out.println("T3 执行");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
t1.start();
t2.start();
t3.start();
单线程池(Executors.newSingleThreadExecutor()
)可以确保任务按提交顺序依次执行。所有任务都会在同一个线程中运行,保证了顺序性。
示例代码:
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(() -> {
// 线程 T1 的任务
System.out.println("T1 执行");
});
executor.submit(() -> {
// 线程 T2 的任务
System.out.println("T2 执行");
});
executor.submit(() -> {
// 线程 T3 的任务
System.out.println("T3 执行");
});
executor.shutdown();
synchronized
synchronized
是 Java 中的一个关键字,用于实现线程同步,确保多个线程对共享资源的访问是互斥的。它通过锁机制来保证同一时刻只有一个线程可以执行被 synchronized
保护的代码块,从而避免数据不一致和线程安全问题。
示例代码:
class Task {
synchronized void executeTask(String taskName) {
System.out.println(taskName + " 执行");
}
}
public class Main {
public static void main(String[] args) {
Task task = new Task();
new Thread(() -> task.executeTask("T1")).start();
new Thread(() -> task.executeTask("T2")).start();
new Thread(() -> task.executeTask("T3")).start();
}
}
CompletableFuture
CompletableFuture
是 Java 8 引入的类,属于 java.util.concurrent
包。它是一个功能强大的工具,用于处理异步编程。CompletableFuture
允许创建、操作和组合任务,可以说是处理异步任务的一个灵活和强大的解决方案。
示例代码:
import java.util.concurrent.CompletableFuture;
public class CompletableFutureSequentialExecution {
public static void main(String[] args) {
// 创建第一个任务 T1
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
System.out.println("T1 is running on thread: " + Thread.currentThread().getName());
// 模拟任务运行
sleep(1000);
});
// 链接任务 T2 到 T1 之后
future = future.thenRunAsync(() -> {
System.out.println("T2 is running on thread: " + Thread.currentThread().getName());
sleep(1000);
});
// 链接任务 T3 到 T2 之后
future = future.thenRunAsync(() -> {
System.out.println("T3 is running on thread: " + Thread.currentThread().getName());
sleep(1000);
});
// 等待所有任务完成
future.join();
}
// 辅助方法用于模拟延迟
private static void sleep(long milliseconds) {
try {
Thread.sleep(milliseconds);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
本文介绍了 6 种保证线程 T1、T2 和 T3 顺序执行的方法,依次如下:
join()
:通过 join()
方法让一个线程等待另一个线程完成。CountDownLatch
:通过计数器实现线程的顺序执行。Semaphore
:通过许可管理实现线程的顺序执行。synchronized
:通过锁机制确保线程同步。CompletableFuture
:通过异步任务的链式调用实现顺序执行。