ThreadPoolExecutor的排队行为是否可以自定义以优先于排队创建新线程?

时间:2013-08-14 16:53:59

标签: java java.util.concurrent threadpoolexecutor

ThreadPoolExecutor doc说

  

如果正在运行corePoolSize或更多线程,则始终执行Executor   喜欢排队请求而不是添加新线程。


  

如果有多个corePoolSize但小于maximumPoolSize   如果线程正在运行,则只有在队列出现时才会创建新线程   满。

有没有办法让执行者更喜欢新的线程创建,直到达到最大值,即使有超过核心大小的线程,然后开始排队?如果队列达到其最大大小,任务将被拒绝。如果在处理繁忙突发之后超时设置将启动并将线程删除到核心大小,那将是很好的。我认为背后的原因是优先排队以便允许限制;但是,此自定义还将允许队列主要用作尚未运行的任务列表。

4 个答案:

答案 0 :(得分:4)

无法使用ThreadPoolExecutor获得此确切行为。

但是,这里有几个解决方案:

  1. 考虑一下,

    • 如果正在运行少于corePoolSize个线程,则将为排队coorPoolSize个线程之前排队的每个项目创建一个新线程。

    • 只有在队列已满并且运行的线程少于maximumPoolSize时才会创建新线程。

    因此,将ThreadPoolExecutor包装在一个类中,该类监视项目排队的速度。然后,在提交许多项目时将核心池大小更改为更高的值。这将导致每次提交新项目时都会创建一个新线程。

    当提交突发完成时,需要再次手动减少核心池大小,以便线程自然超时。如果你担心繁忙的突发可能会突然结束,导致手动方法失败,请务必使用allowCoreThreadTimeout

  2. 创建固定的线程池,allowCoreThreadTimeout

    不幸的是,这在低提交突发期间使用了更多线程,并且在零流量期间不存储空闲线程。

  3. 如果您有时间,需要和倾向,请使用第一种解决方案,因为它可以处理更广泛的提交频率,因此在灵活性方面是更好的解决方案。

    否则使用第二种解决方案。

答案 1 :(得分:2)

只需执行Executors.newFixedThreadPool所做的操作,并将coremax设置为相同的值。这是来自Java 6的newFixedThreadPool源代码:

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

如果你有现有的,你可以做什么:

ThreadPoolExecutor tpe = ... ;
tpe.setCorePoolSize(tpe.getMaxPoolSize());

编辑:正如William在评论中指出的那样,这意味着所有线程都是核心线程,因此所有线程都不会超时并终止。要更改此行为,只需使用ThreadPoolExecutor.allowCoreThreadTimeout(true)即可。这将使得线程可以超时并在执行器未被使用时被扫除。

答案 2 :(得分:1)

似乎您的偏好是在低活动期间的最小延迟。为此我只需将corePoolSize设置为max,让额外的线程挂起。在高活动时间内,这些线程无论如何都会存在。在低活动时期,它们的存在不会产生那么大的影响。如果你希望它们死掉,你可以设置核心线程超时。

这样,所有线程将始终可用于尽快执行任务。

答案 3 :(得分:0)

CustomBlockingQueue

package com.gunjan;

import java.util.concurrent.BlockingQueue;

public abstract class CustomBlockingQueue<E> implements BlockingQueue<E> {

public BlockingQueue<E> blockingQueue;

public CustomBlockingQueue(BlockingQueue blockingQueue) {
    this.blockingQueue = blockingQueue;
}

@Override
final public boolean offer(E e) {
    return false;
}

final public boolean customOffer(E e) {
    return blockingQueue.offer(e);
}
}

ThreadPoolBlockingQueue

package com.gunjan;

import java.util.Collection;
import java.util.Iterator;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;

public class ThreadPoolBlockingQueue<E> extends CustomBlockingQueue<E> {

    public ThreadPoolBlockingQueue(BlockingQueue blockingQueue) {
        super(blockingQueue);
    }

    @Override
    public E remove() {
        return this.blockingQueue.remove();
    }

    @Override
    public E poll() {
        return this.blockingQueue.poll();
    }

    @Override
    public E element() {
        return this.blockingQueue.element();
    }

    @Override
    public E peek() {
        return this.blockingQueue.peek();
    }

    @Override
    public int size() {
        return this.blockingQueue.size();
    }

    @Override
    public boolean isEmpty() {
        return this.blockingQueue.isEmpty();
    }

    @Override
    public Iterator<E> iterator() {
        return this.blockingQueue.iterator();
    }

    @Override
    public Object[] toArray() {
        return this.blockingQueue.toArray();
    }

    @Override
    public <T> T[] toArray(T[] a) {
        return this.blockingQueue.toArray(a);
    }

    @Override
    public boolean containsAll(Collection<?> c) {
        return this.blockingQueue.containsAll(c);
    }

    @Override
    public boolean addAll(Collection<? extends E> c) {
        return this.blockingQueue.addAll(c);
    }

    @Override
    public boolean removeAll(Collection<?> c) {
        return this.blockingQueue.removeAll(c);
    }

    @Override
    public boolean retainAll(Collection<?> c) {
        return this.blockingQueue.retainAll(c);
    }

    @Override
    public void clear() {
        this.blockingQueue.clear();
    }

    @Override
    public boolean add(E e) {
        return this.blockingQueue.add(e);
    }

    @Override
    public void put(E e) throws InterruptedException {
        this.blockingQueue.put(e);
    }

    @Override
    public boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException {
        return this.blockingQueue.offer(e, timeout, unit);
    }

    @Override
    public E take() throws InterruptedException {
        return this.blockingQueue.take();
    }

    @Override
    public E poll(long timeout, TimeUnit unit) throws InterruptedException {
        return this.blockingQueue.poll(timeout, unit);
    }

    @Override
    public int remainingCapacity() {
        return this.blockingQueue.remainingCapacity();
    }

    @Override
    public boolean remove(Object o) {
        return this.blockingQueue.remove(o);
    }

    @Override
    public boolean contains(Object o) {
        return this.blockingQueue.contains(o);
    }

    @Override
    public int drainTo(Collection<? super E> c) {
        return this.blockingQueue.drainTo(c);
    }

    @Override
    public int drainTo(Collection<? super E> c, int maxElements) {
        return this.blockingQueue.drainTo(c, maxElements);
    }
}

RejectedExecutionHandlerImpl

package com.gunjan;

import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;

public class RejectedExecutionHandlerImpl implements RejectedExecutionHandler {

    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        boolean inserted = ((CustomBlockingQueue) executor.getQueue()).customOffer(r);
        if (!inserted) {
            throw new RejectedExecutionException();
        }
    }
}

CustomThreadPoolExecutorTest

package com.gunjan;

import java.util.concurrent.*;

public class CustomThreadPoolExecutorTest {

public static void main(String[] args) throws InterruptedException {
    LinkedBlockingQueue linkedBlockingQueue = new LinkedBlockingQueue<Runnable>(500);
    CustomBlockingQueue customLinkedBlockingQueue = new ThreadPoolBlockingQueue<Runnable>(linkedBlockingQueue);
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 100, 60, TimeUnit.SECONDS,
            customLinkedBlockingQueue, new RejectedExecutionHandlerImpl());


    for (int i = 0; i < 750; i++) {
        try {
            threadPoolExecutor.submit(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(1000);
                        System.out.println(threadPoolExecutor);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        } catch (RejectedExecutionException e) {
            e.printStackTrace();
        }

    }

    threadPoolExecutor.shutdown();
    threadPoolExecutor.awaitTermination(Integer.MAX_VALUE, TimeUnit.MINUTES);
    System.out.println(threadPoolExecutor);
}
}