introduction
ThreadPoolExcutor
A JDK
built-in thread pool, but also we often use the method to create when you create a thread pool. Thread pool a little understanding of the students know, the thread pool is a typical pool of cache design. JDK
Comes with four tasks deny policy, but sometimes we can not meet the real business needs, so in this case we need to customize the policy to refuse to deal with the rejected task thread pool.
- Thread Pool comes deny policy introduced
- How to customize deny policy
First, comes the thread pool rejection policy introduced
JDK comes with the thread pool denial strategy has the following four categories:
1, DiscardPolicy: silently discard task can not be processed without any treatment;
public static class DiscardPolicy implements RejectedExecutionHandler {
public DiscardPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
}
}
2, DiscardOldestPolicy : discard the oldest task in the queue, try to submit the current job again;
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
public DiscardOldestPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
e.getQueue().poll();
e.execute(r);
}
}
}
3, AbortPolicy : direct throw an exception that prevents the system is working properly;
public static class AbortPolicy implements RejectedExecutionHandler {
public AbortPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException("Task " + r.toString() +
" rejected from " +
e.toString());
}
}
4, CallerRunsPolicy : will be divided to the calling thread to perform the task, run the task currently being discarded, so do not really discard task, but the thread performance is likely to submit a sharp decline
public static class CallerRunsPolicy implements RejectedExecutionHandler {
public CallerRunsPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
r.run();
}
}
}
We can see that the first three strategies are discards the original task. However, in some business scenarios, we can not discard the brutal task. A fourth refused strategy is to deal with discarded task by starting a thread pool thread, but the problem is that even the thread pool idle, it will not perform tasks discarded, but wait for the main thread calls the thread pool to perform the task, until the end of the mission.
Second, comes the thread pool rejection policy introduced
In the definition of the thread pool, we can see that there is a unified policy to refuse to implement the interface, as follows:
public interface RejectedExecutionHandler {
void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
}
We can define processing strategy in line with their own business scenarios according to their business needs. We can look at some of the mainstream framework is how to define your own self-processing strategy.
1, Netty threads in the pool rejection policy
private static final class NewThreadRunsPolicy implements RejectedExecutionHandler {
NewThreadRunsPolicy() {
super();
}
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
try {
final Thread t = new Thread(r, "Temporary task executor");
t.start();
} catch (Throwable e) {
throw new RejectedExecutionException(
"Failed to start a new thread", e);
}
}
}
Source can be seen from the above, Netty
the task of handling is not discarded, and this idea CallerRunsPolicy
similar advantages. In just Netty
a custom frame reject strategy is to complete the task of discarded thread through the new work, but we come to look at it in a thread is created, no constraint conditions, as long as resources allow to continue to create new thread for processing.
2, Dubbo threads in the pool rejection policy
public class AbortPolicyWithReport extends ThreadPoolExecutor.AbortPolicy {
protected static final Logger logger = LoggerFactory.getLogger(AbortPolicyWithReport.class);
private final String threadName;
private final URL url;
private static volatile long lastPrintTime = 0;
private static Semaphore guard = new Semaphore(1);
public AbortPolicyWithReport(String threadName, URL url) {
this.threadName = threadName;
this.url = url;
}
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
String msg = String.format("Thread pool is EXHAUSTED!" +
" Thread Name: %s, Pool Size: %d (active: %d, core: %d, max: %d, largest: %d), Task: %d (completed: %d)," +
" Executor status:(isShutdown:%s, isTerminated:%s, isTerminating:%s), in %s://%s:%d!",
threadName, e.getPoolSize(), e.getActiveCount(), e.getCorePoolSize(), e.getMaximumPoolSize(), e.getLargestPoolSize(),
e.getTaskCount(), e.getCompletedTaskCount(), e.isShutdown(), e.isTerminated(), e.isTerminating(),
url.getProtocol(), url.getIp(), url.getPort());
logger.warn(msg);
dumpJStack();
throw new RejectedExecutionException(msg);
}
private void dumpJStack() {
//省略实现
}
}
Dubbo
Custom refused strategy, print the log output current thread stack information and perform JDK
a default deny policy.