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
相关产品推荐
相关产品推荐

