如何让ScheduledExecutor线程绑定固定参数及synchronized用法正确性验证
问题1:ScheduledExecutor线程绑定固定参数实现方案
问题原因
你当前的代码虽然为每个参数单独提交了定时任务,但ScheduledThreadPool的线程是共享复用的,任务和线程没有绑定关系,同一参数对应的定时任务多次调度时可能被线程池内的任意线程执行,因此会出现不同线程处理不同参数的现象。
解决方案
最可靠的实现方式是为每个参数单独创建单线程的ScheduledExecutor,每个调度器内只有唯一线程,对应参数的任务永远由该线程执行,天然满足绑定要求,且5个任务依然可以并发执行:
// 存储每个参数对应的独立调度器,服务关闭时需要统一销毁 private List<ScheduledExecutorService> argExecutors = new ArrayList<>(); // 初始化逻辑 int threadIdx = 0; for (ArgumentType arg : ARGUMENT_TYPES) { // 每个参数对应一个单线程调度器,线程名按顺序生成 ScheduledExecutorService singleExecutor = Executors.newSingleThreadScheduledExecutor( ExecutorServiceUtils.createThreadFactory("process-" + threadIdx++) ); argExecutors.add(singleExecutor); // 提交当前参数的定时任务,永远由该调度器的唯一线程执行 singleExecutor.scheduleAtFixedRate(() -> work(arg), SCHEDULED_TASK_INITIAL_DELAY_MILLIS, 1L, TimeUnit.MILLISECONDS); }
问题2:synchronized使用合理性分析
结论
该synchronized的使用既不正确也无必要,还会带来性能损耗和并发安全隐患:
- 锁粒度不合理:你锁的是当前类实例,如果其他操作myMap的逻辑没有加同一把锁,这个同步块完全无法阻止其他线程并发修改map值,
entry.getValue().equals(WorkValue.READY)的判断依然可能读取到旧值,出现并发问题。 - 性能损耗严重:同步块放在循环内部,每次遍历entry都要抢锁,完全浪费了ConcurrentHashMap的并发特性,多线程场景下大部分时间会消耗在锁竞争上。
正确实现
直接使用ConcurrentHashMap自带的原子操作即可,无需额外加锁:
for (Map.Entry<String, WorkValue> entry : myMap.entrySet()) { String key = entry.getKey(); // replace是原子操作,只有当前值为READY时才会修改为PROCESSING,返回true代表修改成功 if (myMap.replace(key, WorkValue.READY, WorkValue.PROCESSING)) { ids.add(key); } }
内容的提问来源于stack exchange,提问作者Mark
相关产品推荐
相关产品推荐

