使用Java线程池调用Future#get方法后程序无异常挂起问题求解
问题原因分析
- 你定义的线程池参数是问题的核心诱因:核心线程数1、最大线程数1、工作队列使用
SynchronousQueue、拒绝策略配置为DiscardPolicy。 - 提交第一个任务taskOne时,核心线程处于空闲状态,直接分配核心线程执行taskOne,taskOne会休眠5秒,此时核心线程被完全占用。
- 提交第二个任务taskTwo时的处理流程:
- 核心线程已占满,尝试将任务放入工作队列
SynchronousQueue本身不存储任何任务,必须有空闲线程同步接收任务才能入队成功,此时没有空闲线程,入队直接失败- 最大线程数已达到上限1,无法创建新的非核心线程执行任务
- 触发
DiscardPolicy拒绝策略:该策略会直接静默丢弃被拒绝的任务,不会抛出任何异常,也不会给调用方任何通知
- taskOne执行完成后,
taskOne.get()正常返回null,因此第一行日志task one ,result: null正常打印。 - 后续执行
taskTwo.get()时,由于taskTwo已经被丢弃,对应的Future对象永远不会进入完成状态,无超时参数的get()方法会一直阻塞等待,因此程序直接挂起,不会抛出任何异常。
修复建议
- 方案1:更换拒绝策略,比如改用默认的
AbortPolicy,任务被拒绝时会直接抛出RejectedExecutionException,可以快速感知到任务被拒绝的问题 - 方案2:调用
get方法时指定超时时间,例如taskTwo.get(10, TimeUnit.SECONDS),避免程序无限期阻塞 - 方案3:如果业务允许任务排队等待,更换为容量合适的阻塞队列(比如
ArrayBlockingQueue),让第二个任务可以进入队列等待核心线程空闲后执行
内容的提问来源于stack exchange,提问作者rookie
相关产品推荐
相关产品推荐

