问题
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