有三个线程T1,T2,T3 怎么确保都按顺序执行?

确保多个线程按顺序执行(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();
    }
}

选择建议

  1. 简单场景:使用Thread.join()或单线程池
  2. 需要灵活性:使用CountDownLatchSemaphore
  3. Java 8+项目:使用CompletableFuture(代码简洁)
  4. 复杂同步控制:使用Lock/Condition
  5. 线程间通信:使用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通常是最推荐的方式。


作 者:南烛
链 接:https://www.itnotes.top/archives/1041
来 源:IT笔记
文章版权归作者所有,转载请注明出处!


上一篇
下一篇