改变线程池的工作模式,你试过吗
改变线程池的工作模式,你试过吗
1.线程池默认的工作模式
有任务来了才创建核心线程;
当核心线程满了之后把任务堆积到工作队列中;
当工作队列满了后扩容线程池,一直到线程个数达到 maximumPoolSize 为止;
如果队列已满且达到了最大线程后还有任务进来,按照拒绝策略处理;当线程数大于核心线程数时,线程等待 keepAliveTime 后还是没有任务需要处理的话,收缩线程到核心线程数。
如果我想改变线程池的工作模式
核心线程数上限,启用非核心线程数,非核心线程数满了,再放到工作队列中
该怎么做呢?
2.激进的线程池工作模式
2.1 重写队列的 offer 方法
首先创建一个类,继承 LinkedBlockingQueue 重写 offer 方法 直接返回false 什么都不存 放出假消息 我的队列已经满了
真正存队列的另外在写一个方法 ( 见后文 )
public class MyQueue extends LinkedBlockingQueue { @Override public boolean offer(Object o) { System.out.println(Thread.currentThread().getName()+" :: 尝试进入队列 当前队列元素个数 :"+super.size()); return false; } }
2.2 自定义线程池并自定义拒绝策略
如果想达到我们想要的效果 , 那么在核心线程数上限,存放线程任务时,报一个假消息,让线程池误认为工作队列已经满了
这时就会创建非核心线程,执行线程任务, 如果非核心线程数也上限了,那么就会执行拒绝策略
我们设想的是,非核心线程数上限了,这时把线程任务才真正的丢到工作队列中去 那么相应的,就应该自定义一个拒绝策略
所以我们需要重写工作队列和拒绝策略,当然最好自己创建线程工厂
package com.sgg.javaerror100.弹性线程池; import java.util.concurrent.*; import java.util.stream.IntStream; /** * @author sz * @DATE 2022/4/27 16:22 */ public class MyThreadPool { public static MyQueue workQueue = new MyQueue(); public static void main(String[] args) { ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor( 2, 10, 10, TimeUnit.MINUTES, workQueue, new ThreadFactory() { int core = 0; int nocore = 0; @Override public Thread newThread(Runnable r) { String threadName = core < 2 ? "核心线程" : "非核心线程"; if ("核心线程" .equals(threadName)) { return new Thread(r, threadName + " ( " + (++core) +" )"); }else { return new Thread(r, threadName +" ( " + (++nocore)+" )"); } } }, new RejectedExecutionHandler() { @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { System.out.println(Thread.currentThread().getName() + " :: 触发拒绝策略"); workQueue.doOffer(r); } } ); IntStream.rangeClosed(1, 13).forEach(i -> { System.out.println("i = " + i); poolExecutor.execute(() -> { System.out.println("poolExecutor.getPoolSize() = " + poolExecutor.getPoolSize()); System.out.println(Thread.currentThread().getName() + " :: 执行 " + i); try { TimeUnit.DAYS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } }); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } ); } }
代码创建了一个 核心线程数为2,非核心线程数为8,存活时长为10分钟,并且自定义了线程工厂与拒绝策略 的 线程池
往线程池中提交了13个线程任务 而我们的线程总数只有10个 势必会有3个线程任务 触发拒绝策略
触发拒绝策略时,调用了 MyQueue.doOffer 方法,真正将线程任务放入队列中
public class MyQueue extends LinkedBlockingQueue { public boolean doOffer(Object o) { System.out.println(Thread.currentThread().getName()+" :: 真正进入队列 当前队列元素个数 :"+ (super.size()+1)); return super.offer(o); } @Override public boolean offer(Object o) { System.out.println(Thread.currentThread().getName()+" :: 尝试进入队列 当前队列元素个数 :"+super.size()); return false; } }
这样写能不能达到我们想要的效果呢 ? 看代码演示
2.3 代码演示
输出结果如下
i = 1 poolExecutor.getPoolSize() = 1 核心线程 ( 1 ) :: 执行 1 i = 2 poolExecutor.getPoolSize() = 2 核心线程 ( 2 ) :: 执行 2 i = 3 main :: 尝试进入队列 当前队列元素个数 :0 poolExecutor.getPoolSize() = 3 非核心线程 ( 1 ) :: 执行 3 i = 4 main :: 尝试进入队列 当前队列元素个数 :0 poolExecutor.getPoolSize() = 4 非核心线程 ( 2 ) :: 执行 4 i = 5 main :: 尝试进入队列 当前队列元素个数 :0 poolExecutor.getPoolSize() = 5 非核心线程 ( 3 ) :: 执行 5 i = 6 main :: 尝试进入队列 当前队列元素个数 :0 poolExecutor.getPoolSize() = 6 非核心线程 ( 4 ) :: 执行 6 i = 7 main :: 尝试进入队列 当前队列元素个数 :0 poolExecutor.getPoolSize() = 7 非核心线程 ( 5 ) :: 执行 7 i = 8 main :: 尝试进入队列 当前队列元素个数 :0 poolExecutor.getPoolSize() = 8 非核心线程 ( 6 ) :: 执行 8 i = 9 main :: 尝试进入队列 当前队列元素个数 :0 poolExecutor.getPoolSize() = 9 非核心线程 ( 7 ) :: 执行 9 i = 10 main :: 尝试进入队列 当前队列元素个数 :0 poolExecutor.getPoolSize() = 10 非核心线程 ( 8 ) :: 执行 10 i = 11 main :: 尝试进入队列 当前队列元素个数 :0 main :: 触发拒绝策略 main :: 真正进入队列 当前队列元素个数 :1 i = 12 main :: 尝试进入队列 当前队列元素个数 :1 main :: 触发拒绝策略 main :: 真正进入队列 当前队列元素个数 :2 i = 13 main :: 尝试进入队列 当前队列元素个数 :2 main :: 触发拒绝策略 main :: 真正进入队列 当前队列元素个数 :3
2.4 结论
由输出结果可知 确实做到了 先创建核心线程执行线程任务,再由非核心线程执行线程任务,最后在放到队列中,也就是说,我们是可以改变线程池的工作模式的
#Java开发##内推##笔经##Java#