java中semaphore用于限制runnable并发数,装饰者模式用于动态增强任务行为;二者职责分离但可协同:semaphore管“能否执行”,装饰器管“如何更好执行”,如timedsemaphorerunnable既限流又计时。

Java中把Semaphore和Runnable组合起来,主要是为任务加一层“并发闸门”——控制同时能跑几个;而装饰者模式不是用来管数量的,是给任务动态加行为的,比如记录耗时、重试逻辑或统一日志。两者可以一起用,但目标不同、职责分离。
用Semaphore限制Runnable任务的实际并发数
核心思路是:每个Runnable在执行前先acquire()一个许可,执行完再release()。没拿到许可的任务会自动阻塞,等前面的任务释放后才能继续。
- 创建Semaphore时指定许可数,例如
new Semaphore(3)表示最多3个任务并行 - Runnable实现类里持有该Semaphore引用,run()中必须包裹acquire()/release(),且推荐用try-finally确保释放不遗漏
- 如果不想让线程无限等待,可用
tryAcquire(long timeout, TimeUnit unit)设置超时,获取失败就跳过或降级处理
用装饰者模式增强Runnable的行为
直接实现Runnable写死逻辑难复用,装饰者模式让你把通用增强功能(如统计执行时间、捕获异常、添加上下文)抽离成独立组件,再“套”在任意Runnable外面。
- 定义一个装饰器接口,比如
interface RunnableDecorator extends Runnable,或更通用的泛型接口Decorator<t></t> - 写具体装饰器类,构造时接收原始Runnable,内部持有一个引用;run()方法里先做增强动作(如记录开始时间),再调用原始run(),最后收尾(如打印耗时)
- 可叠加使用:A装饰B,C再装饰A,形成链式增强,无需修改原始任务代码
二者协同:带限流+增强能力的任务封装
把Semaphore控制和装饰逻辑合到一个Runnable实现里,既限并发,又自带可观测性或健壮性。这不是强行拼凑,而是分层控制:Semaphore管“能不能跑”,装饰逻辑管“怎么跑得更稳更好”。
- 例如写一个
TimedSemaphoreRunnable类,它既是Runnable,又接收Semaphore和被包装的Runnable作为参数 - run()中先acquire(),再用System.nanoTime()打点计时,调用原始任务,finally里release()并打印耗时
- 这样每次提交任务时,你拿到的是一个“自带限流+计时”的完整单元,线程池只管调度,不用关心底层细节
注意几个关键细节
实际编码中容易忽略但影响稳定性的点:
- Semaphore的acquire()可能抛出InterruptedException,务必捕获并正确处理(如恢复中断状态
Thread.currentThread().interrupt()) - release()必须放在finally块里,否则任务中途异常退出会导致许可泄露,后续所有任务永久阻塞
- 装饰器不要在构造阶段执行业务逻辑,所有增强动作应严格放在run()内,保证延迟生效、线程安全
- 如果Runnable需要返回值,原始接口不支持,得改用Callable+Future,或者用装饰器内部设result字段+join()同步获取
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











