Java 线程池使用 Future,任务没完成啥意思

2022-06-07 17:24:08 +08:00
 frank1256

线程池,核心数 10 个,我循环 2 次,等待第一次 10 个线程结束,无法立刻提交第二次的 10 个线程? 同一时刻只会有 10 个线程跑,咋回事啊,大佬指点迷津 提示的 Not completed,难道 call()方法执行完毕,不算一个任务完成吗

代码如图

报错

finished100
finished100
finished100
finished100
finished100
finished100
finished100
finished100
finished100
finished100
finished one repeate
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.ExecutorCompletionService$QueueingFuture@48140564[Not completed, task = java.util.concurrent.Executors$RunnableAdapter@7c30a502[Wrapped task = java.util.concurrent.FutureTask@1d251891[Not completed, task = executor.ExecutorDemo$1@49e4cb85]]] rejected from java.util.concurrent.ThreadPoolExecutor@2133c8f8[Running, pool size = 10, active threads = 2, queued tasks = 0, completed tasks = 10]
	at java.base/java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2055)
	at java.base/java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:825)
	at java.base/java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1355)
	at java.base/java.util.concurrent.ExecutorCompletionService.submit(ExecutorCompletionService.java:184)
	at executor.ExecutorDemo.main(ExecutorDemo.java:34)


2789 次点击
所在节点    Java
25 条回复
gengzi
2022-06-07 17:39:17 +08:00
跟你配置的线程池参数有关系,核心和最大线程数都是 10 ,阻塞队列为 1 ,当前线程数大于 maxpoolsize ,并且阻塞队列已满,就走拒绝策略了,默认的拒绝策略应该是 抛异常
frank1256
2022-06-07 17:44:45 +08:00
@gengzi 我在内部循环的时候只提交了 10 次,只会有 10 个线程存在,然后用 future.get 阻塞,直到 10 个线程完成任务.此时阻塞队列里任务 0,第二次循环的,还是提交了 10 个任务,应该还是由一开始的 10 个线程完成才对. 整个流程在同一时刻只会有 10 个任务
q1angch0u
2022-06-07 17:50:40 +08:00
使用 ArrayBlockingQueue 有界任务队列,若有新的任务需要执行时,线程池会 [创建] 新的线程,直到 [创建] 的线程数量达到 corePoolSize 时,则会将新的任务加入到等待队列中。若等待队列已满,即超过 ArrayBlockingQueue 初始化的容量,则继续创建线程,直到线程数量达到 maximumPoolSize 设置的最大线程数量,若大于 maximumPoolSize ,则执行拒绝策略。注意是创建线程,旧线程是不会复用的,因为你的 corePollSize 是 10 ,所以第一次建的 10 个线程是不会被销毁的。
q1angch0u
2022-06-07 17:52:11 +08:00
@frank1256 #2 threadPoolExecutor 是线程池啊,放线程的地儿,一开始的 10 个和第二波的 10 个并不是相同的线程,为啥会 [由一开始的 10 个线程] 完成呢? 0-9 和 10-19 是没关系的。
q1angch0u
2022-06-07 17:52:49 +08:00
你可以把 corePoolSize 改成 0 试试,刚开始的 10 个会超时回收,应该就没问题了。
frank1256
2022-06-07 17:58:04 +08:00
@q1angch0u 额.可是我希望的是 20 个任务,都是由一开始创建的 10 个线程来完成. corePoolSize 设 0,是会再建 10 个,但我已经有 10 个存活了,我没必要去在建 10 个额
twinsdestiny
2022-06-07 17:59:26 +08:00
@frank1256 那就不要把 keepAaliveTime 设置为 0
q1angch0u
2022-06-07 17:59:46 +08:00
@frank1256 #6 那你就不应该再新建 10 个线程,前十个线程叫小王,后十个线程叫小红,小红怎么能叫小王呢…
frank1256
2022-06-07 18:01:45 +08:00
@q1angch0u 我没再建 10 个线程啊,提交到线程池就新建一个线程了吗?不先检查已经建的线程是否空闲吗?
q1angch0u
2022-06-07 18:05:51 +08:00
@frank1256 #9 第一问:是的,submit 就是新建线程;第二问:线程空闲了啊,但是它目前活着的比 corePoolSize 小,所以不会销毁呀。
frank1256
2022-06-07 18:08:22 +08:00
@q1angch0u 😨
frank1256
2022-06-07 18:12:11 +08:00
@q1angch0u 没有方法,让我的第二次 10 个任务依然由第一次建的 10 个线程执行吗?
q1angch0u
2022-06-07 18:12:40 +08:00
@frank1256 或者也可以设置 allowCoreThreadTimeout=true
q1angch0u
2022-06-07 18:13:24 +08:00
@frank1256 #12 有办法让小红变成小王吗……
frank1256
2022-06-07 18:21:58 +08:00
@q1angch0u 好吧,我得再试试
q1angch0u
2022-06-07 18:35:03 +08:00
@frank1256 对不起,我好像误人子弟了。
evilnull
2022-06-07 18:52:57 +08:00
线程池线程的第一个任务是线程创建时直接分配的,之后所有的任务是从队列里获取的。
你第二次提交 10 个任务时,核心线程已满,不会再创建核心线程,任务会先提交到队列里,核心线程会从队列里取任务去执行。由于你队列长度是 1 ,而且任务提交速度比线程从队列里取任务速度快,会有部分任务提交时队列是满的,最终走到拒绝策略。
可以将线程池队列长度调大点,或者使用 SynchronousQueue 。
frank1256
2022-06-07 18:59:00 +08:00
frank1256
2022-06-07 18:59:45 +08:00
@evilnull 好像是这么回事
frank1256
2022-06-07 19:00:13 +08:00
@evilnull 谢谢

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/857959

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX