确保多个线程按顺序执行(T1→T2→T3)是常见的线程同步问题。以下是几种解决方案:
1. 使用Thread.join()(最简单)
public class ThreadJoinExample {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
System.out.println("T1执行");
}, "T1");
Thread t2 = new Thread(() -> {
System.out.println("T2执行");
}, "T2");
Thread t3 = new Thread(() -> {
System.out.println("T3执行");
}, "T3");
// 按顺序启动并等待
t1.start();
t1.join(); // 等待T1结束
t2.start();
t2.join(); // 等待T2结束
t3.start();
t3.join();
}
}
2. 使用CountDownLatch(更灵活)
import java.util.concurrent.CountDownLatch;
public class CountDownLatchExample {
public static void main(String[] args) {
CountDownLatch latch1 = new CountDownLatch(1);
CountDownLatch latch2 = new CountDownLatch(1);
Thread t1 = new Thread(() -> {
System.out.println("T1执行");
latch1.countDown(); // 通知T2可以开始
});
Thread t2 = new Thread(() -> {
try {
latch1.await(); // 等待T1完成
System.out.println("T2执行");
latch2.countDown(); // 通知T3可以开始
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread t3 = new Thread(() -> {
try {
latch2.await(); // 等待T2完成
System.out.println("T3执行");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
// 可以按任意顺序启动线程
t1.start();
t2.start();
t3.start();
}
}
3. 使用CyclicBarrier
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierExample {
public static void main(String[] args) {
CyclicBarrier barrier1 = new CyclicBarrier(2); // T1和T2之间的屏障
CyclicBarrier barrier2 = new CyclicBarrier(2); // T2和T3之间的屏障
Thread t1 = new Thread(() -> {
System.out.println("T1执行");
try {
barrier1.await(); // 通知T2可以继续
} catch (Exception e) {
e.printStackTrace();
}
});
Thread t2 = new Thread(() -> {
try {
barrier1.await(); // 等待T1完成
System.out.println("T2执行");
barrier2.await(); // 通知T3可以继续
} catch (Exception e) {
e.printStackTrace();
}
});
Thread t3 = new Thread(() -> {
try {
barrier2.await(); // 等待T2完成
System.out.println("T3执行");
} catch (Exception e) {
e.printStackTrace();
}
});
t1.start();
t2.start();
t3.start();
}
}
4. 使用单线程池(最简单高效)
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class SingleThreadExecutorExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newSingleThreadExecutor();
// 任务会按提交顺序执行
executor.submit(() -> {
System.out.println("T1执行");
});
executor.submit(() -> {
System.out.println("T2执行");
});
executor.submit(() -> {
System.out.println("T3执行");
});
executor.shutdown();
}
}
5. 使用CompletableFuture(Java 8+)
import java.util.concurrent.CompletableFuture;
public class CompletableFutureExample {
public static void main(String[] args) {
CompletableFuture<Void> future = CompletableFuture
.runAsync(() -> System.out.println("T1执行"))
.thenRun(() -> System.out.println("T2执行"))
.thenRun(() -> System.out.println("T3执行"));
future.join(); // 等待所有任务完成
}
}
6. 使用wait/notify机制
public class WaitNotifyExample {
private static final Object lock = new Object();
private static int state = 1; // 状态标识
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
synchronized (lock) {
while (state != 1) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("T1执行");
state = 2;
lock.notifyAll();
}
});
Thread t2 = new Thread(() -> {
synchronized (lock) {
while (state != 2) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("T2执行");
state = 3;
lock.notifyAll();
}
});
Thread t3 = new Thread(() -> {
synchronized (lock) {
while (state != 3) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("T3执行");
}
});
t1.start();
t2.start();
t3.start();
}
}
7. 使用Lock和Condition
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockConditionExample {
private static final Lock lock = new ReentrantLock();
private static final Condition condition1 = lock.newCondition();
private static final Condition condition2 = lock.newCondition();
private static int flag = 1;
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
lock.lock();
try {
while (flag != 1) {
condition1.await();
}
System.out.println("T1执行");
flag = 2;
condition2.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
});
Thread t2 = new Thread(() -> {
lock.lock();
try {
while (flag != 2) {
condition2.await();
}
System.out.println("T2执行");
flag = 3;
condition2.signal(); // 通知T3
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
});
Thread t3 = new Thread(() -> {
lock.lock();
try {
while (flag != 3) {
condition2.await();
}
System.out.println("T3执行");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
});
t1.start();
t2.start();
t3.start();
}
}
8. 使用Semaphore
import java.util.concurrent.Semaphore;
public class SemaphoreExample {
public static void main(String[] args) {
// 初始时,T1可以执行,T2和T3需要等待
Semaphore s1 = new Semaphore(1);
Semaphore s2 = new Semaphore(0);
Semaphore s3 = new Semaphore(0);
Thread t1 = new Thread(() -> {
try {
s1.acquire();
System.out.println("T1执行");
s2.release(); // 释放T2的信号量
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread t2 = new Thread(() -> {
try {
s2.acquire();
System.out.println("T2执行");
s3.release(); // 释放T3的信号量
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread t3 = new Thread(() -> {
try {
s3.acquire();
System.out.println("T3执行");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
t1.start();
t2.start();
t3.start();
}
}
选择建议
- 简单场景:使用
Thread.join()或单线程池 - 需要灵活性:使用
CountDownLatch或Semaphore - Java 8+项目:使用
CompletableFuture(代码简洁) - 复杂同步控制:使用
Lock/Condition - 线程间通信:使用
wait/notify
性能考虑
- 单线程池最简单,但所有任务在同一个线程中执行
CompletableFuture可以利用线程池并行执行其他不相关的任务- 信号量和锁机制更灵活,适合复杂的同步场景
实际应用场景
// 实际项目中,更常见的做法是使用线程池和Future
ExecutorService executor = Executors.newFixedThreadPool(3);
Future<?> f1 = executor.submit(() -> {
// 任务1
return "T1结果";
});
Future<?> f2 = executor.submit(() -> {
f1.get(); // 等待任务1完成
// 任务2
return "T2结果";
});
Future<?> f3 = executor.submit(() -> {
f2.get(); // 等待任务2完成
// 任务3
return "T3结果";
});
f3.get(); // 等待所有任务完成
executor.shutdown();
选择哪种方案取决于具体需求和项目架构,单线程池和CompletableFuture通常是最推荐的方式。