【Java】如何改变线程池的工作模式

改变线程池的工作模式,你试过吗

1.线程池默认的工作模式

  1. 有任务来了才创建核心线程;
  1. 当核心线程满了之后把任务堆积到工作队列中;
  2. 当工作队列满了后扩容线程池,一直到线程个数达到 maximumPoolSize 为止;
  3. 如果队列已满且达到了最大线程后还有任务进来,按照拒绝策略处理;当线程数大于核心线程数时,线程等待 keepAliveTime 后还是没有任务需要处理的话,收缩线程到核心线程数。

如果我想改变线程池的工作模式

核心线程数上限,启用非核心线程数,非核心线程数满了,再放到工作队列中

该怎么做呢?

image-20220427210340131

2.激进的线程池工作模式

2.1 重写队列的 offer 方法

首先创建一个类,继承 LinkedBlockingQueue 重写 offer 方法 直接返回false 什么都不存 放出假消息 我的队列已经满了

真正存队列的另外在写一个方法 ( 见后文 )

public class MyQueue extends LinkedBlockingQueue {
​
​@Overridepublic boolean offer(Object o) {System.out.println(Thread.currentThread().getName()+"  :: 尝试进入队列  当前队列元素个数 :"+super.size());return false;}
}

2.2 自定义线程池并自定义拒绝策略

image-20220427211159336

image-20220427211745058

如果想达到我们想要的效果 , 那么在核心线程数上限,存放线程任务时,报一个假消息,让线程池误认为工作队列已经满了

这时就会创建非核心线程,执行线程任务, 如果非核心线程数也上限了,那么就会执行拒绝策略

我们设想的是,非核心线程数上限了,这时把线程任务才真正的丢到工作队列中去 那么相应的,就应该自定义一个拒绝策略

所以我们需要重写工作队列和拒绝策略,当然最好自己创建线程工厂

image-20220427212327830

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;@Overridepublic 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() {@Overridepublic 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);}
​@Overridepublic boolean offer(Object o) {System.out.println(Thread.currentThread().getName()+"  :: 尝试进入队列  当前队列元素个数 :"+super.size());return false;}
}

这样写能不能达到我们想要的效果呢 ? 看代码演示

2.3 代码演示

idea64_ZLDbBM46uD

输出结果如下

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 结论

由输出结果可知 确实做到了 先创建核心线程执行线程任务,再由非核心线程执行线程任务,最后在放到队列中,也就是说,我们是可以改变线程池的工作模式的

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/287220.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【组合数学】生成函数

目录 1.形式幂级数2.生成函数性质3.生成函数求解递推关系4.生成函数在计数问题中的应用 1.形式幂级数 生成函数是解决计数问题的一种有效方法&#xff0c;它的中心思想是&#xff1a;对于一个有限或无限数列 a 0 , a 1 , a 2 , . . . {a_0,a_1,a_2,...} a0​,a1​,a2​,...&am…

Numpy教程(一)—— ndarray:多维数组对象

前言 该numpy学习笔记参考了菜鸟教程网、b站up主 孙兴华zz 的《孙兴华中文讲python数据分析三部曲》以及《北理-python数据分析与展示》&#xff0c;课本推荐使用《利用python进行数据分析》 Numpy简介&#xff1a; NumPy(Numerical Python) 是 Python 语言的一个扩展程序库&a…

Python----进程的注意点

1. 进程的注意点介绍 进程之间不共享全局变量主进程会等待所有的子进程执行结束再结束 2. 进程之间不共享全局变量 import multiprocessing import time# 定义全局变量 g_list list()# 添加数据的任务 def add_data():for i in range(5):g_list.append(i)print("add:&…

性能测试什么时候开始?性能测试流程介绍

性能测试什么时候开始? 一般在系统功能稳定没有大的缺陷之后开始执行。但前期准备工作可以从系统需求分析时就开始&#xff1a;性能目标制定、场景获取、环境申请等。 一、制定性能测试目标 在特定的并发用户数下测试特定场景的响应时间 在一定的响应时间的要求下来测试特…

STM32单片机项目实例:基于TouchGFX的智能手表设计(5)硬件驱动层程序设计

STM32单片机项目实例&#xff1a;基于TouchGFX的智能手表设计&#xff08;5&#xff09;硬件驱动层程序设计 目录 一、 概述 二、 新建工程与外设配置 三、 TouchGFX配置 四、 增加TouchGFX关键驱动 一、 概述 本文内容主要进行工程新建&#xff0c;硬件外设的配置以及添加…

使用Alpha Vantage API和Python进行金融数据分析

Alpha Vantage通过一套强大且开发者友好的数据API和电子表格&#xff0c;提供实时和历史的金融市场数据。从传统资产类别&#xff08;例如股票、ETF、共同基金&#xff09;到经济指标&#xff0c;从外汇汇率到大宗商品&#xff0c;从基本数据到技术指标&#xff0c;Alpha Vanta…

Google Analystics账号的创建

1&#xff0c;空账号 如果您原来没有用过谷歌分析&#xff0c;点开后会是下面的页面&#xff0c;点击页面中央的开始衡量&#xff08;start measuring&#xff09; 2&#xff0c;已有过账号 如果您原本有过账号需要创建新账号&#xff0c;需要点击主页左下角的管理&#xff…

JMUer-网络新技术课程期末考试复习整理

✏️write in front✏️ &#x1f4dd;个人主页&#xff1a;陈丹宇jmu &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd;​ &#x1f649;联系作者&#x1f648;by QQ&#xff1a;813942269&#x1f427; &#x1f308;致亲爱的读者&#xff1a;很高兴你…

Java继承特性(学习推荐版)——java三大特性之一,子类extends父类

定义 Java支持单继承和多层继承&#xff0c;但不支持多继承 # 子类构造器及super用法 解释&#xff1a;子类构造器&#xff0c;注意是子类的构造器&#xff0c;不是子类的方法的第一行默认都会有super()去调用无参构造器&#xff0c;只不过可以省略没写而已。当然也可以自己写…

openwrt 搭建web

折腾 软路由 有几年了&#xff0c;最近试了下 移动的 IPV6, 既然可以拿到 公网的 IPV6&#xff0c; 所以想折腾下, 经过不懈努力 实现了&#xff1a;通过 ipv4/ipv6 地址访问我的 web站点 (白飘不花钱的方式) 1 动态DNS 折腾 DDNS 无非是想 白飘 公网IP&#xff0c;但是 仅仅…

VueStu02-创建一个Vue实例

一、核心步骤 1.准备容器 准备一个盒子div。 2.引包 从官网引包&#xff0c;有开发版本和生产版本之分。 3.创建Vue实例 创建一个Vue实例&#xff0c;new Vue()。 4.指定配置项 指定配置项&#xff0c;用于渲染数据 。 el&#xff1a;指定挂载点。知道自己将来要管理的是…

【MySQL】 表的操作

// 创建表 create table 表名();// 查看表结构 desc 表名;// 新增一列表信息 alter table 表名 add 字段名 字段类型 (after 原表某一字段名);// 删除一列表信息 alter table 表名 drop 字段名;// 修改表字段名字 alter table 表名 change 原字段名 新字段名 类型; // 新字…