如何实现阻塞ThreadPoolExecutor

时间:2017-03-30 05:51:34

标签: java multithreading threadpoolexecutor

我需要实现阻止ThreadPoolExecutor

这是我们企业应用程序中非常关键的要求。

它会执行类似if ThreadPoolExecutor.submit()ThreadPoolExecutor.execute()方法块的操作,直到线程被释放以获取新任务。

但是在当前的实现ThreadPoolExecutor.submit()ThreadPoolExecutor.execute()方法中,如果所有池化线程都忙,则抛出RejectedExecutionException异常。

例如,以下代码抛出RejectedExecutionException

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class BlockingTPE {
    public static void main(String[] args) {
        ArrayBlockingQueue queue = new ArrayBlockingQueue(3);
        ThreadPoolExecutor tpExe = new ThreadPoolExecutor(1, 3, 30, TimeUnit.SECONDS, queue);
        int numJobs = 50;
        for (int i = 1; i <= numJobs; i++) {
            try {
                tpExe.submit(new WorkerThread(i));
                System.out.println("Added#" + (i));
            } catch (RejectedExecutionException e) {
                e.printStackTrace();
            }
        }
    }
}

class WorkerThread implements Runnable {
    int jobId;

    public WorkerThread(int jobId) {
        this.jobId = jobId;
    }

    public void run() {
        try {
            Thread.sleep(1000);
        }
        catch (Exception excep) {
        }
    }
}

1 个答案:

答案 0 :(得分:3)

由于ThreadPoolExecutor的javadoc状态:

  

使用给定的初始参数和创建一个新的ThreadPoolExecutor   默认线程工厂和被拒绝的执行处理程序。

被拒绝的执行程序处理程序是AbortPolicy的实例,如果队列不接受其他任务,则会调用该实例。 javadoc的行为:

  

始终抛出RejectedExecutionException。

因此阻塞队列对您没有任何影响。我以这种方式更改了代码,它运行时没有任何问题:

public static void main(String[] args) {
    ThreadPoolExecutor executor = new ThreadPoolExecutor(
            1, 3, 30, TimeUnit.SECONDS, new ArrayBlockingQueue(3));
    try {
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        int numJobs = 50;
        for (int i = 1; i <= numJobs; i++) {
            try {
                executor.submit(new WorkerThread(i));
                System.out.println("Added#" + (i));
            } catch (RejectedExecutionException e) {
                e.printStackTrace();
            }
        }
    } finally {
        executor.shutdown();
    }
}

您必须做出的决定是:

  • 使用未绑定的队列来支持所有延迟的任务。例如LinkedBlockingQueue
  • 使用绑定队列,让当前线程执行不适合完整队列的任务。例如,请参阅我在答案中发布的代码。
  • 如果有界队列已满,则丢弃任务。例如,使用ThreadPoolExecutor.DiscardPolicy作为被拒绝的执行处理程序。