You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中如何通过示例使用Semaphore替换Thread.join方法

使用Semaphore替换Thread.join()实现方案

原程序的核心运行逻辑是:主线程启动10个工作线程,阻塞等待所有工作线程执行终止(无论正常运行结束还是异常退出)后,主线程才会结束运行。使用Semaphore实现完全等价效果的思路非常直接:

  • 初始化一个初始许可数为0的Semaphore实例,总共有10个工作线程,主线程需要收集到10个许可才会解除阻塞
  • 每个工作线程在自身执行逻辑完全结束时,释放1个许可;为了对齐join()的原生行为(线程无论因何种原因终止,join()都会返回),许可释放操作必须放在finally块中,避免线程异常退出时漏释放导致主线程永久挂起
  • 主线程启动完全部工作线程后,一次性尝试获取10个许可,此时主线程会阻塞,直到所有工作线程都释放了对应许可,效果和循环调用每个线程的join()方法完全一致

实现注意:不要把release()操作放在业务逻辑的正常返回路径上,必须放在finally块覆盖所有退出场景,否则线程被中断、抛出运行时异常时会出现许可缺失,和原程序行为不一致。

完整可运行代码如下:

import java.util.concurrent.*;

public class JoinP {
    public static void main(String[] args) {
        int numberofthreads = 10;
        Thread[] t = new Thread[numberofthreads];
        // 初始化信号量,初始许可为0
        final Semaphore doneSemaphore = new Semaphore(0);

        for (int j = 0; j < numberofthreads; j++) {
            (t[j] = new Thread(new ExThread(doneSemaphore))).start();
        }

        try {
            // 等待获取10个许可,即等待所有10个线程执行完成
            doneSemaphore.acquire(numberofthreads);
        } catch (Exception e) {
            return; 
        }
    }

    static class ExThread implements Runnable {
        private final Semaphore doneSemaphore;

        ExThread(Semaphore doneSemaphore) {
            this.doneSemaphore = doneSemaphore;
        }

        public void run() {
            try {
                TimeUnit.SECONDS.sleep(10);
            } catch (Exception e) {
                return;
            } finally {
                // 无论正常执行还是异常退出,都释放一个许可,标记当前线程执行完毕
                doneSemaphore.release();
            }
        }
    }
}

运行上述代码的效果和原join版本完全一致:10个工作线程并发启动后各自休眠10秒,主线程会一直阻塞到所有工作线程全部执行完成才退出,不会出现提前返回、漏等线程的情况。

内容的提问来源于stack exchange,提问作者JohnD

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 08:54:21