Java 指定ThreadPoolExecutor问题

Java 指定ThreadPoolExecutor问题,java,multithreading,threadpool,Java,Multithreading,Threadpool,是否有任何方法可以创建始终至少有5个线程、最多20个线程以及任务无限队列(意味着没有任务被拒绝)的Executor 我尝试了新的ThreadPoolExecutor(5,20,60L,TimeUnit.SECONDS,queue) 我想到了队列的所有可能性: new LinkedBlockingQueue() // never runs more than 5 threads new LinkedBlockingQueue(1000000) // runs more than 5 threads

是否有任何方法可以创建始终至少有5个线程、最多20个线程以及任务无限队列(意味着没有任务被拒绝)的Executor

我尝试了新的
ThreadPoolExecutor(5,20,60L,TimeUnit.SECONDS,queue)
我想到了队列的所有可能性:

new LinkedBlockingQueue() // never runs more than 5 threads
new LinkedBlockingQueue(1000000) // runs more than 5 threads, only when there is more than 1000000 tasks waiting
new ArrayBlockingQueue(1000000) // runs more than 5 threads, only when there is more than 1000000 tasks waiting
new SynchronousQueue() // no tasks can wait, after 20, they are rejected

而且没有一个线程可以正常工作。

ThreadPoolExecutor的javadocs非常清楚,一旦创建了
corePoolSize
线程,只有在队列已满时才会创建新线程。因此,如果您将
core
设置为5,将
max
设置为20,您将永远无法获得所需的行为


但是,如果将
core
max
都设置为20,则只有当所有20个线程都忙时,任务才会添加到队列中。当然,这会使您的“最少5个线程”要求变得有点毫无意义,因为所有20个线程都将保持活动状态(直到它们空闲掉为止)。

也许这样的要求对您适用?我刚把它搅起来,请戳一下。基本上,它实现了一个溢出线程池,用于为底层
ThreadPoolExecutor

我看到它有两个主要的缺点:

  • submit()
    上缺少返回的未来对象。但也许这不是你的问题
  • 提交作业时,辅助队列将仅清空到
    ThreadPoolExecutor
    中。必须有一个优雅的解决方案,但我现在还没有看到。如果您知道将有一个稳定的任务流进入
    StusMagicExecutor
    ,那么这可能不是问题。(“可能”是关键词。)一种选择可能是让您提交的任务在完成后戳到
    StusMagicExecutor
斯图的魔法执行人:

public class StusMagicExecutor extends ThreadPoolExecutor {
    private BlockingQueue<Runnable> secondaryQueue = new LinkedBlockingQueue<Runnable>();  //capacity is Integer.MAX_VALUE.

    public StusMagicExecutor() {
        super(5, 20, 60L, SECONDS, new SynchronousQueue<Runnable>(true), new RejectionHandler());  
    }
    public void queueRejectedTask(Runnable task) {
        try {
            secondaryQueue.put(task);
        } catch (InterruptedException e) {
            // do something
        }
    }
    public Future submit(Runnable newTask) {
        //drain secondary queue as rejection handler populates it
        Collection<Runnable> tasks = new ArrayList<Runnable>();
        secondaryQueue.drainTo(tasks);

        tasks.add(newTask);

        for (Runnable task : tasks)
             super.submit(task);

        return null; //does not return a future!
    }
}

class RejectionHandler implements RejectedExecutionHandler {
    public void rejectedExecution(Runnable runnable, ThreadPoolExecutor executor) {
        ((StusMagicExecutor)executor).queueRejectedTask(runnable);
    }
}
公共类StusMagicExecutor扩展ThreadPoolExecutor{
private BlockingQueue secondaryQueue=new LinkedBlockingQueue();//容量为Integer.MAX_值。
公共行政主管(){
super(5,20,60L,秒,新的SynchronousQueue(true),新的RejectionHandler());
}
公共无效队列拒绝任务(可运行任务){
试一试{
secondaryQueue.put(任务);
}捕捉(中断异常e){
//做点什么
}
}
公共未来提交(可运行的newTask){
//在拒绝处理程序填充辅助队列时将其排出
收集任务=新建ArrayList();
secondaryQueue.drainTo(任务);
任务。添加(newTask);
for(可运行任务:任务)
超级提交(任务);
return null;//不返回未来!
}
}
类RejectionHandler实现RejectedExecutionHandler{
public void rejectedExecution(Runnable Runnable,ThreadPoolExecutor executor){
((StusMagicExecutor)执行器)。队列拒绝任务(可运行);
}
}

我认为这个问题是该类的一个缺点,并且考虑到构造函数参数组合,它非常容易引起误解。这是一个来自SwingWorker的内部ThreadPoolExecutor的解决方案,我将其制作成一个顶级类。它没有最小值,但至少使用了上界。我唯一不知道的是锁定执行对性能的影响

public class BoundedThreadPoolExecutor extends ThreadPoolExecutor {
    private final ReentrantLock pauseLock = new ReentrantLock();
    private final Condition unpaused = pauseLock.newCondition();
    private boolean isPaused = false;
    private final ReentrantLock executeLock = new ReentrantLock();

    public BoundedThreadPoolExecutor(int maximumPoolSize,
            long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
        super(0, maximumPoolSize, keepAliveTime, unit, workQueue);
    }

    public BoundedThreadPoolExecutor(int maximumPoolSize,
            long keepAliveTime, TimeUnit unit,
        BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
        super(0, maximumPoolSize, keepAliveTime, unit, workQueue,
                threadFactory);
    }

    public BoundedThreadPoolExecutor(int maximumPoolSize,
            long keepAliveTime, TimeUnit unit,
            BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
        super(0, maximumPoolSize, keepAliveTime, unit, workQueue,
                handler);
    }

    public BoundedThreadPoolExecutor(int maximumPoolSize,
            long keepAliveTime, TimeUnit unit,
            BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory,
            RejectedExecutionHandler handler) {
        super(0, maximumPoolSize, keepAliveTime, unit, workQueue,
                threadFactory, handler);
    }

    @Override
    public void execute(Runnable command) {
        executeLock.lock();
        try {
            pauseLock.lock();
            try {
                isPaused = true;
            } finally {
                pauseLock.unlock();
            }
            setCorePoolSize(getMaximumPoolSize());
            super.execute(command);
            setCorePoolSize(0);
            pauseLock.lock();
            try {
                isPaused = false;
                unpaused.signalAll();
            } finally {
                pauseLock.unlock();
            }
        } finally {
            executeLock.unlock();
        }
    }

    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        super.afterExecute(r, t);
        pauseLock.lock();
        try {
            while (isPaused) {
                unpaused.await();
            }
        } catch (InterruptedException ignore) {

        } finally {
            pauseLock.unlock();
        }
    }
}
public类BoundedThreadPoolExecutor扩展ThreadPoolExecutor{
private final ReentrantLock pauseLock=new ReentrantLock();
private final Condition unpaused=pauseLock.newCondition();
私有布尔值isPaused=false;
private final ReentrantLock executeLock=new ReentrantLock();
public BoundedThreadPoolExecutor(int maximumPoolSize,
long keepAliveTime、时间单位、阻塞队列(工作队列){
super(0,maximumPoolSize,keepAliveTime,unit,workQueue);
}
public BoundedThreadPoolExecutor(int maximumPoolSize,
长keepAliveTime,时间单位,
BlockingQueue工作队列,ThreadFactory ThreadFactory){
超级(0,maximumPoolSize,keepAliveTime,unit,workQueue,
螺纹加工厂);
}
public BoundedThreadPoolExecutor(int maximumPoolSize,
长keepAliveTime,时间单位,
BlockingQueue工作队列,RejectedExecutionHandler){
超级(0,maximumPoolSize,keepAliveTime,unit,workQueue,
经办人);
}
public BoundedThreadPoolExecutor(int maximumPoolSize,
长keepAliveTime,时间单位,
BlockingQueue工作队列,ThreadFactory ThreadFactory,
RejectedExecutionHandler(处理程序){
超级(0,maximumPoolSize,keepAliveTime,unit,workQueue,
螺纹加工厂、处理厂);
}
@凌驾
public void execute(Runnable命令){
executeLock.lock();
试一试{
pauseLock.lock();
试一试{
isPaused=真;
}最后{
pauseLock.unlock();
}
setCorePoolSize(getMaximumPoolSize());
super.execute(命令);
setCorePoolSize(0);
pauseLock.lock();
试一试{
isPaused=false;
unpaused.signalAll();
}最后{
pauseLock.unlock();
}
}最后{
executeLock.unlock();
}
}
@凌驾
执行后受保护的无效(可运行的r、可丢弃的t){
super.afterExecute(r,t);
pauseLock.lock();
试一试{
while(isPaused){
等待;
}
}捕获(中断异常忽略){
}最后{
pauseLock.unlock();
}
}
}

你说它不起作用是什么意思?一个例外?这太接近了:甘道夫和萨蒙!急诊室随时都会来。那个讨厌的老鹰在哪里…“闲置”永远不会发生,除非你们说所有的核心线程都可能死亡。无论如何,如果不能正确使用,就看不到核心和最大尺寸的意义