CopyOnWriteArrayList与newScheduledThreadPool配合异常问题排查
问题原因分析
核心问题出在两个关键点上:
- CopyOnWriteArrayList迭代器的限制:CopyOnWriteArrayList的迭代器是基于容器的快照生成的,它天生不支持修改操作(包括
remove())。当你调用iterator.remove()时,会直接抛出UnsupportedOperationException。 - 定时任务的异常处理规则:你的定时任务里把这个异常包装成
RuntimeException抛出,但整个任务没有捕获该异常。根据ScheduledExecutorService的运行规则:如果重复执行的定时任务抛出未捕获的异常,后续所有的定时执行都会被直接终止,这就是为什么你的任务只执行了一次就停了。
移除iterator.remove()后正常的原因:
去掉这条语句后,定时任务里不再触发异常,任务就能按照你设定的5秒间隔持续执行下去。
修复删除元素的正确方式:
如果需要完成"移除已完成任务"的逻辑,不能用迭代器的remove(),可以改用批量删除的方式,比如:
scheduledExecutorService.scheduleAtFixedRate(() -> { List<FactRec> completedTasks = new ArrayList<>(); // 先遍历收集已完成的任务 for (FactRec curr : list) { if(curr.f.isDone()){ try { System.out.println("\n------------------------------"); System.out.printf("%d! = %s%n", curr.num, curr.f.get()); System.out.println("------------------------------"); completedTasks.add(curr); } catch (InterruptedException | ExecutionException e) { throw new RuntimeException(e); } } else{ System.out.println("Task is still running"); } } // 批量移除已完成的任务 list.removeAll(completedTasks); }, 0, 5, TimeUnit.SECONDS);
内容的提问来源于stack exchange,提问作者Cody
相关产品推荐
相关产品推荐

