Java 具有多个限制的线程池
我想要一个线程池,提供最多X个线程来处理任务,到目前为止没有问题。但是,每个提交的任务都可以指定一个特定限制的IO目标(例如Y) 因此,提交的IOTask返回目标“google.com”,限制为4(Y),池的全局限制为16(X)。我想提交10个google.com-tasks,其中只有4个并行处理,池中有12个线程可供其他任务使用Java 具有多个限制的线程池,java,multithreading,scala,concurrency,pool,Java,Multithreading,Scala,Concurrency,Pool,我想要一个线程池,提供最多X个线程来处理任务,到目前为止没有问题。但是,每个提交的任务都可以指定一个特定限制的IO目标(例如Y) 因此,提交的IOTask返回目标“google.com”,限制为4(Y),池的全局限制为16(X)。我想提交10个google.com-tasks,其中只有4个并行处理,池中有12个线程可供其他任务使用 我怎样才能做到这一点呢?嗯。。。很抱歉,现有的ExecutorService不允许这样精细的控制。您可能需要自己扩展ExecutorService类来添加此功能,或者
我怎样才能做到这一点呢?嗯。。。很抱歉,现有的
ExecutorService
不允许这样精细的控制。您可能需要自己扩展ExecutorService类来添加此功能,或者使用两个单独的固定线程池,一个容量为4,另一个容量为12。实现此功能并不简单,因为每个目标都需要单独的队列(因此等待代码变得复杂得多),或者从一个队列中跳过已满负荷的目标(导致性能开销)。您可以尝试扩展ExecutorService来实现这一点,但扩展似乎并不简单
最新答案/解决方案:
仔细考虑后,阻塞问题的最简单解决方案是拥有阻塞队列(按照正常情况)和队列映射(每个目标一个队列,以及每个目标的可用线程计数)。队列映射仅用于已传递执行的任务(由于该目标已经运行了太多线程)从常规阻塞队列中获取任务后
因此,执行流程如下所示:
- 然后线程将计数减少1,释放锁,运行任务
- 否则,线程将任务放入目标到任务队列的映射(此映射是传递给任务映射的),释放锁,然后返回到阻塞队列等待
- 在锁上同步
- 检查刚刚执行的目标的计数
- 如果计数=0
- 然后检查传递的任务映射中是否存在此目标的任何任务(如果存在),然后释放锁并运行它
- 如果计数不是0,或者传递的映射/队列上没有相同目标的任务,则增加可用计数(对于该目标),释放锁,然后返回到等待阻塞队列
此解决方案避免了任何显著的性能开销,也避免了使用单独的线程来管理队列。这样做的一个想法是扩展ExecutorService,并且在您的类中有两个线程池,一个线程池的容量为4,另一个线程池的容量为12
然后实现所需的方法,并根据提交的IOTasks,将任务定向到希望其进入的池。使用线程总数计数器和HashMap,计算当前尝试访问站点X的线程数。如果要启动新线程,请调用检查w的同步方法aits(while循环内的wait()),直到哈希映射中的线程数小于4且线程总数小于16。然后递增两个计数器并启动线程。当线程完成时,它应调用第二个同步方法,该方法递减计数器并调用notify()以更具体的方式思考一些答案
这里有一些同步问题需要仔细考虑,以确保计数器永远不会超过4。不幸的是,一旦您在beforeExecute内,就太晚了,但是能够简单地知道在给定时间运行多少任务可能会让您开始执行。您可以包装两个ExecutorService实例在自定义类中,手动管理任务的提交,如下所示:
class ExecutorWrapper {
private ExecutorService ioExec = Executors.newFixedThreadPool(4);
private ExecutorService genExec = Executors.newFixedThreadPool(12);
public Future<?> submit(final IOTask task) {
return ioExec.submit(task);
}
public Future<?> submit(final Runnable task) {
return genExec.submit(task);
}
}
interface IOTask extends Runnable {}
类执行器包装器{
私有ExecutorService ioExec=Executors.newFixedThreadPool(4);
private ExecutorService genExec=Executors.newFixedThreadPool(12);
公共未来提交(最终任务){
返回ioExec.submit(任务);
}
公共未来提交(最终可运行任务){
返回genExec.submit(任务);
}
}
接口IOTask扩展可运行{}
这允许您使用4个线程来执行IO操作,剩下12个线程来执行其他任务。但这意味着,在线程可用之前,尝试启动新线程的操作本身会被等待/通知阻止。我想尽量减少使用的线程数。是的,您是对的。这是一个错误的答案。I w如果可以的话,我会投反对票。这就是我基本上求助的方法。