我正在寻找一个java线程池,它不会同时运行比系统中的核心更多的线程。此服务通常由ThreadPoolExecutor使用BlockingQueue提供。
但是,如果计划执行新线程,我希望新线程先占其中一个已经运行的线程,并将抢先线程(处于挂起状态)添加到任务队列,一旦新线程完成,它就可以恢复。
有什么建议吗?
答案 0 :(得分:4)
我会创建一个ThreadPoolExecutor的子类。
当您设置ThreadPoolExecutor时,您想要将corePoolSize
和maximumPoolSize
设置为Runtime.getRuntime().availableProcessors()
(请查看Executors.newFixedThreadPool()
以查看其工作原理。)
接下来,您要确保Queue
也实施Deque
。 LinkedBlockingDeque
就是一个例子,但你应该四处寻找,看看哪一款最适合你。 Deque
允许您像LIFO行为一样获得堆栈,这正是您想要的。
由于所有内容(submit()
,invokeAll()
)都会通过execute()
进行汇总,因此您需要覆盖此方法。基本上做你上面描述的:
检查所有线程是否都在运行。如果不是简单地在可用线程上启动新的runnable。如果所有线程都已经运行,那么你需要找到运行最早runnable的线程,停止runnable,在某处重新排队runnable(可能在开头?),然后启动新的runnable。
答案 1 :(得分:1)
ThreadPoolExecutor的想法是避免与创建和销毁线程相关的所有昂贵操作。如果你绝对坚持抢占正在运行的任务,那么你就不会从默认的API中获得它。
如果您愿意允许正在运行的任务完成,而只是抢占尚未开始执行的任务,那么您可以使用类似Stack(LIFO)的BlockingQueue实现。
您还可以通过使用具有不同线程优先级的不同执行程序让任务“抢占”其他任务。实质上,如果操作系统支持时间切片,则优先级较高的执行程序会获得时间片。
否则,您需要一个管理执行的自定义实现。您可以使用SynchronousQueue并让P工作线程等待它。如果客户端调用execute并且SynchronousQueue.offer失败,那么你必须创建一个特殊的工作线程,它抓取其他一个线程并在执行前将它们标记为暂停,并再次标记它们在执行后恢复。