方案一:join

主线程等待子线程的终止。也就是说主线程的代码块中,如果碰到了t.join()方法,此时主线程需要等待(阻塞),等待子线程结束了(Waits for this thread to die.),才能继续执行t.join()之后的代码块。

join()的使用场景:

在很多情况下,主线程创建并启动子线程,如果子线程中要进行大量的耗时运算,主线程将可能早于子线程结束。如果主线程需要知道子线程的执行结果时,就需要等待子线程执行结束了。主线程可以sleep(xx),但这样的xx时间不好确定,因为子线程的执行时间不确定,join()方法比较合适这个场景。

join() 和 sleep() 一样,可以被中断(被中断时,会抛出 InterrupptedException 异常);不同的是,join() 内部调用了 wait(),会出让锁,而 sleep() 会一直保持锁。

public class ThreadSequence {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> System.out.println("线程1执行"));
        Thread t2 = new Thread(() -> System.out.println("线程2执行"));
        Thread t3 = new Thread(() -> System.out.println("线程3执行"));
        
        t1.start();
        t1.join(); // 等待t1执行完成
        
        t2.start();
        t2.join(); // 等待t2执行完成
        
        t3.start();
        t3.join(); // 等待t3执行完成
    }
}

方案二: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("线程1执行");
            latch1.countDown();
        });
        
        Thread t2 = new Thread(() -> {
            try {
                latch1.await(); // 等待线程1完成
                System.out.println("线程2执行");
                latch2.countDown();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        
        Thread t3 = new Thread(() -> {
            try {
                latch2.await(); // 等待线程2完成
                System.out.println("线程3执行");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        
        t1.start();
        t2.start();
        t3.start();
    }
}

方案三:信号量semaphore

import java.util.concurrent.Semaphore;

public class SemaphoreExample {
    private static Semaphore semaphore1 = new Semaphore(1);
    private static Semaphore semaphore2 = new Semaphore(0);
    private static Semaphore semaphore3 = new Semaphore(0);
    
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            try {
                semaphore1.acquire();
                System.out.println("线程1执行");
                semaphore2.release();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        
        Thread t2 = new Thread(() -> {
            try {
                semaphore2.acquire();
                System.out.println("线程2执行");
                semaphore3.release();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        
        Thread t3 = new Thread(() -> {
            try {
                semaphore3.acquire();
                System.out.println("线程3执行");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        
        t1.start();
        t2.start();
        t3.start();
    }
}

方案四:synchronized + wait/notify

public class WaitNotifyExample {
    private static Object lock = new Object();
    private static int count = 1;
    
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            synchronized (lock) {
                while (count != 1) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("线程1执行");
                count = 2;
                lock.notifyAll();
            }
        });
        
        Thread t2 = new Thread(() -> {
            synchronized (lock) {
                while (count != 2) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("线程2执行");
                count = 3;
                lock.notifyAll();
            }
        });
        
        Thread t3 = new Thread(() -> {
            synchronized (lock) {
                while (count != 3) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("线程3执行");
            }
        });
        
        t1.start();
        t2.start();
        t3.start();
    }
}

方案五:使用线程池 + Future

import java.util.concurrent.*;

public class ExecutorServiceExample {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(3);
        
        Future<?> future1 = executor.submit(() -> System.out.println("线程1执行"));
        future1.get(); // 等待线程1完成
        
        Future<?> future2 = executor.submit(() -> System.out.println("线程2执行"));
        future2.get(); // 等待线程2完成
        
        Future<?> future3 = executor.submit(() -> System.out.println("线程3执行"));
        future3.get(); // 等待线程3完成
        
        executor.shutdown();
    }
}

方案六: CompletableFuture

import java.util.concurrent.CompletableFuture;

public class CompletableFutureExample {
    public static void main(String[] args) {
        CompletableFuture.runAsync(() -> System.out.println("线程1执行"))
            .thenRun(() -> System.out.println("线程2执行"))
            .thenRun(() -> System.out.println("线程3执行"))
            .join();
    }
}

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐