ThreadPoolExecutor
简单介绍一下ThreadPoolExecutor的加入规则:
corePoolSize: maximumPoolSize, workQueue;
假设核心线程全部建立,并且不销毁
当前任务加入线程池后, 如果正在执行的任务数量少于corePoolSize, 那么直接加入corePoolSize已经开辟的线程中运行;
但如果运行的任务数量等于corePoolSize时, 该任务会添加到队列, 直到队列放置不下时; 判断存在的线程数是否达到maximumPoolSize,如果没有达到,开辟新线程继续运行.
重写需求如下:
1.线程池中始终保持核心线程数, 当任务加入ThreadPoolExecutor时,如果有空闲线程,自动到空闲线程中运行
2.如果核心线程都在运行, 依然有新加入任务时, 这时如果线程数量少于maximumPoolSize, 创建新线程运行该任务.
3.如果运行的线程数等于maximumPoolSize时, 将请求任务加入队列, 不拒绝任务.
修改如下:
import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; public class MyThreadPoolExecutor extends java.util.concurrent.ThreadPoolExecutor { private final AtomicInteger submittedTaskCount = new AtomicInteger(0); public MyThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, TaskQueue workQueue) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue); workQueue.setExecutor(this); prestartAllCoreThreads(); } //执行完成后计数器减1 @Override protected void afterExecute(Runnable r, Throwable t) { super.afterExecute(r, t); submittedTaskCount.decrementAndGet(); } public int getSubmittedTaskCount() { return submittedTaskCount.get(); } @Override public void execute(Runnable command) { submittedTaskCount.incrementAndGet(); try { super.execute(command); } catch (RejectedExecutionException rx) { if(super.getQueue() instanceof TaskQueue) { final TaskQueue queue = (TaskQueue) (super.getQueue()); try { if (!queue.force(command)) { // 无限队列, 理论上不会失败; submittedTaskCount.decrementAndGet(); throw new RejectedExecutionException("Queue capacity is full."); } } catch(Exception x){ submittedTaskCount.decrementAndGet(); throw new RejectedExecutionException(x); } } else { submittedTaskCount.decrementAndGet(); throw rx; } } } }
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.ThreadPoolExecutor; public class TaskQueue extends LinkedBlockingQueue<Runnable>{ private MyThreadPoolExecutor executor; public TaskQueue(){ super(); } public void setExecutor(MyThreadPoolExecutor executor) { this.executor = executor; } public boolean force(Runnable o) { if (executor.isShutdown()) { throw new RejectedExecutionException("Executor not running, can't force a command into the queue"); } return super.offer(o); //forces the item onto the queue, to be used if the task is rejected } @Override public boolean offer(Runnable o) { int currentPoolThreadSize = executor.getPoolSize(); // 线程数达到最大,添加到队列 if(currentPoolThreadSize >= executor.getMaximumPoolSize()) { return super.offer(o); } // 有空闲线程,直接添加到队列 if(executor.getSubmittedTaskCount() < currentPoolThreadSize) { return super.offer(o); } // 当前线程池数还不是最大,创建线程 if(currentPoolThreadSize < executor.getMaximumPoolSize()){ return false; } return super.offer(o); } }
任务队列继承LinkedBlockingQueue, 无上限队列
测试:
import java.util.concurrent.TimeUnit; public class Main { static MyThreadPoolExecutor mutilSecPool = new MyThreadPoolExecutor(2, 7, 2, TimeUnit.SECONDS, new TaskQueue()); static void print(String s){ for(int i = 0; i < 2; ++i){ System.out.println("当前运行"+s); try { Thread.sleep(1000); }catch (Exception e){ e.printStackTrace(); } } } public static void main(String[] args){ System.out.println("线程池线程数: " + mutilSecPool.getPoolSize()); mutilSecPool.submit(()->print("1")); mutilSecPool.submit(()->print("2")); System.out.println("线程池线程数: " + mutilSecPool.getPoolSize()); mutilSecPool.submit(()->print("3")); mutilSecPool.submit(()->print("4")); mutilSecPool.submit(()->print("5")); mutilSecPool.submit(()->print("6")); mutilSecPool.submit(()->print("7")); mutilSecPool.submit(()->print("8")); mutilSecPool.submit(()->print("9")); mutilSecPool.submit(()->print("10")); System.out.println("线程池线程数: " + mutilSecPool.getPoolSize()); try { Thread.sleep(10000); System.out.println("线程池线程数: " + mutilSecPool.getPoolSize()); }catch (Exception e){ e.printStackTrace(); } mutilSecPool.shutdown(); } }
测试出来的结果基本符合预期的, 只是第二次打印线程池线程数目的时候比预期多了一个,这个原因还没有查清楚
参考:点击打开链接
参考:点击打开链接
如果需要更加完善的,建议参考tomcat ThreadPoolExecutor源码