How to implement blocking ThreadPoolExecutor

99封情书 提交于 2019-12-11 06:55:46

问题


I need to implement blocking ThreadPoolExecutor.

This is a very crucial requirement in our enterprise application.

It would do something like if ThreadPoolExecutor.submit() or ThreadPoolExecutor.execute() method blocks until a thread gets freed up for picking up a new task.

But in current implementation ThreadPoolExecutor.submit() and ThreadPoolExecutor.execute() methods throw RejectedExecutionException exception if all pooled threads get busy.

For example following code throws 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:


As the javadoc of ThreadPoolExecutor states:

Creates a new ThreadPoolExecutor with the given initial parameters and default thread factory and rejected execution handler.

The rejected executor handler is an instance of AbortPolicy which will be called if the queue does not accept another task. The behavior as of the javadoc:

Always throws RejectedExecutionException.

Hence the blocking queue does not have any effect for you. I changed your code this way and it runs without any issues:

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();
    }
}

The decision you have to make is:

  • use an unbound queue to support all delayed tasks. For example LinkedBlockingQueue.
  • use a bound queue and let the current thread execute the task which does not fit into the full queue. For example see the code I posted along my answer.
  • discard tasks if the bounded queue is full. For example use ThreadPoolExecutor.DiscardPolicy as rejected execution handler.


来源:https://stackoverflow.com/questions/43109547/how-to-implement-blocking-threadpoolexecutor

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!