項目中有一個需求:給線程池提交任務的時候,如果任務隊列已滿,需要ThreadPoolExecutor.execute調用阻塞等待。google了相關的資料,記錄在這裏,供有同樣需求的同行參考。
ThreadPoolExecutor相關的幾個點:
(1)execute提交任務的時候,會調用指定隊列的offer方法,如果offer方法返回失敗,則表示隊列已滿。如果此時,corePoolSize < maximumPoolSize 會發起新的線程執行新提交的任務;如果 corePoolSize == maximumPoolSize, 則任務提交失敗,會調用RejectedExecutionHandler處理
(2)java提供了四個內置的RejectedExecutionHandler, 如
/**
* A handler for rejected tasks that throws a
* {@code RejectedExecutionException}.
*/
public static class AbortPolicy implements RejectedExecutionHandler {
/**
* Creates an {@code AbortPolicy}.
*/
public AbortPolicy() { }
/**
* Always throws RejectedExecutionException.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
* @throws RejectedExecutionException always
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException("Task " + r.toString() +
" rejected from " +
e.toString());
}
}
/**
* A handler for rejected tasks that silently discards the
* rejected task.
*/
public static class DiscardPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code DiscardPolicy}.
*/
public DiscardPolicy() { }
/**
* Does nothing, which has the effect of discarding task r.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
}
}
/**
* A handler for rejected tasks that discards the oldest unhandled
* request and then retries {@code execute}, unless the executor
* is shut down, in which case the task is discarded.
*/
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code DiscardOldestPolicy} for the given executor.
*/
public DiscardOldestPolicy() { }
/**
* Obtains and ignores the next task that the executor
* would otherwise execute, if one is immediately available,
* and then retries execution of task r, unless the executor
* is shut down, in which case task r is instead discarded.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
e.getQueue().poll();
e.execute(r);
}
}
}
解法1: 重寫隊列的offer方法,讓其變爲一個阻塞調用
使用這種方法時,線程數最多隻能到corePoolSize個,相當於maximumPoolSize的設置無效;
/**
* 重寫offer爲阻塞操作
*/
private static class MyBlockingQueue<T> extends LinkedBlockingQueue<T> {
public MyBlockingQueue(int size) {
super(size);
}
@Override
public boolean offer(T t) {
try {
put(t);
return true;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return false;
}
}
/**
* 固定線程池, block when queue is filled up
*/
public static ThreadPoolExecutor newFixedThreadPool(int nThreads, int queueSize, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(
nThreads, nThreads, 0L, TimeUnit.SECONDS, new MyBlockingQueue<>(queueSize), threadFactory);
}
解法2: 基於java信號量
public class BoundedExecutor {
private final Executor exec;
private final Semaphore semaphore;
public BoundedExecutor(Executor exec, int bound) {
this.exec = exec;
this.semaphore = new Semaphore(bound);
}
public void submitTask(final Runnable command)
throws InterruptedException, RejectedExecutionException {
semaphore.acquire();
try {
exec.execute(new Runnable() {
public void run() {
try {
command.run();
} finally {
semaphore.release();
}
}
});
} catch (RejectedExecutionException e) {
semaphore.release();
throw e;
}
}
}