面试笔记——线程池

线程池的核心参数(原理)

public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler)
  • corePoolSize 核心线程数目
  • maximumPoolSize 最大线程数目 = (核心线程+救急线程的最大数目)
  • keepAliveTime 生存时间 : 救急线程的生存时间,生存时间内没有新任务,此线程资源会释放
  • unit 时间单位 :救急线程的生存时间单位,如秒、毫秒等
  • workQueue :当没有空闲核心线程时,新来任务会加入到此队列排队,队列满会创建救急线程执行任务
  • threadFactory 线程工厂 :可以定制线程对象的创建,例如设置线程名字、是否是守护线程等
  • handler 拒绝策略:当所有线程都在繁忙,workQueue 也放满时,会触发拒绝策略

在这里插入图片描述
使用Demo:

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;public class ThreadPoolDemo implements Runnable {public static void main(String[] args) {//创建阻塞队列LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<>(100);ArrayBlockingQueue<Runnable> arrayBlockingQueue = new ArrayBlockingQueue<>(5);//创建工厂ThreadFactory threadFactory = new ThreadFactory() {AtomicInteger atomicInteger = new AtomicInteger(1);@Overridepublic Thread newThread(Runnable r) {//创建线程把任务传递进去Thread thread = new Thread(r);//设置线程名称thread.setName("MyThread: "+atomicInteger.getAndIncrement());return thread;}};ThreadPoolExecutor pool  = new ThreadPoolExecutor(2,5,1,TimeUnit.SECONDS,arrayBlockingQueue,threadFactory,new ThreadPoolExecutor.DiscardOldestPolicy());for (int i = 0; i < 100; i++) {pool.submit(new ThreadPoolDemo());}pool.shutdown();}@Overridepublic void run() {//执行业务System.out.println(Thread.currentThread().getName()+" 进来了");try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+"出去了");}
}

线程池中常见的阻塞队列

workQueue:当没有空闲核心线程时,新来任务会加入到此队列排队,队列满会创建救急线程执行任务。

  1. ArrayBlockingQueue:基于数组结构的有界阻塞队列,FIFO。
  2. LinkedBlockingQueue:基于链表结构的有界阻塞队列,FIFO。
  3. DelayedWorkQueue :是一个优先级队列,它可以保证每次出队的任务都是当前队列中执行时间最靠前的
  4. SynchronousQueue:不存储元素的阻塞队列,每个插入操作都必须等待一个移出操作。

ArrayBlockingQueue的LinkedBlockingQueue区别:在这里插入图片描述

确定核心线程数

  • IO密集型任务:核心线程数大小设置为2N+1(N为当前CPU的核数)
    • 一般来说:文件读写、DB读写、网络请求等
  • CPU密集型任务:核心线程数大小设置为N+1
    • 一般来说:计算型代码、Bitmap转换、Gson转换等

查看机器的CPU核数:

public static void main(String[] args) {//查看机器的CPU核数System.out.println(Runtime.getRuntime().availableProcessors());
}

参考回答:

  • 高并发、任务执行时间短 :( CPU核数+1 ),减少线程上下文的切换
  • 并发不高、任务执行时间长
    • IO密集型的任务 : (CPU核数 * 2 + 1)
    • 计算密集型任务 :( CPU核数+1 )
  • 并发高、业务执行时间长,解决这种类型任务的关键不在于线程池而在于整体架构的设计,看看这些业务里面某些数据是否能做缓存是第一步,增加服务器是第二步,至于线程池的设置,设置参考上一条

线程池的种类

在java.util.concurrent.Executors类中提供了大量创建连接池的静态方法,以下四种比较常见。
1. 创建使用固定线程数的线程池 ——适用于任务量已知,相对耗时的任务

public static ExecutorService newFixedThreadPool(int nThreads) {return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
}

核心线程数与最大线程数一样,没有救急线程
阻塞队列是LinkedBlockingQueue,最大容量为Integer.MAX_VALUE
举例:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class FixedThreadPoolCase {static class FixedThreadDemo implements Runnable{@Overridepublic void run() {String name = Thread.currentThread().getName();for (int i = 0; i < 2; i++) {System.out.println(name + ":" + i);}}}public static void main(String[] args) throws InterruptedException {//创建一个固定大小的线程池,核心线程数和最大线程数都是3ExecutorService executorService = Executors.newFixedThreadPool(3);for (int i = 0; i < 5; i++) {executorService.submit(new FixedThreadDemo());Thread.sleep(10);}executorService.shutdown();}}

运行结果:

pool-1-thread-1:0
pool-1-thread-1:1
pool-1-thread-2:0
pool-1-thread-2:1
pool-1-thread-3:0
pool-1-thread-3:1
pool-1-thread-1:0
pool-1-thread-1:1
pool-1-thread-2:0
pool-1-thread-2:1

2. 单线程化的线程池,它只会用唯一的工作线程来执行任 务,保证所有任务按照指定顺序(FIFO)执行——适用于按照顺序执行的任务

public static ExecutorService newSingleThreadExecutor() {return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()));
}

核心线程数和最大线程数都是1
阻塞队列是LinkedBlockingQueue,最大容量为Integer.MAX_VALUE

举例:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class NewSingleThreadCase {static int count = 0;static class Demo implements Runnable {@Overridepublic void run() {count++;System.out.println(Thread.currentThread().getName() + ":" + count);}}public static void main(String[] args) throws InterruptedException {//单个线程池,核心线程数和最大线程数都是1ExecutorService exec = Executors.newSingleThreadExecutor();for (int i = 0; i < 10; i++) {exec.execute(new Demo());Thread.sleep(5);}exec.shutdown();}}

运行结果:

pool-1-thread-1:1
pool-1-thread-1:2
pool-1-thread-1:3
pool-1-thread-1:4
pool-1-thread-1:5
pool-1-thread-1:6
pool-1-thread-1:7
pool-1-thread-1:8
pool-1-thread-1:9
pool-1-thread-1:10

3. 可缓存线程池——适合任务数比较密集,但每个任务执行时间较短的情况

public static ExecutorService newCachedThreadPool() {return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());
}

核心线程数为0
最大线程数是Integer.MAX_VALUE
阻塞队列为SynchronousQueue:不存储元素的阻塞队列,每个插入操作都必须等待一个移出操作。

举例:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class CachedThreadPoolCase {static class Demo implements Runnable {@Overridepublic void run() {String name = Thread.currentThread().getName();try {//修改睡眠时间,模拟线程执行需要花费的时间Thread.sleep(100);System.out.println(name + "执行完了");} catch (InterruptedException e) {e.printStackTrace();}}}public static void main(String[] args) throws InterruptedException {//创建一个缓存的线程,没有核心线程数,最大线程数为Integer.MAX_VALUEExecutorService exec = Executors.newCachedThreadPool();for (int i = 0; i < 10; i++) {exec.execute(new Demo());Thread.sleep(1);}exec.shutdown();}}

运行结果:

pool-1-thread-1执行完了
pool-1-thread-2执行完了
pool-1-thread-3执行完了
pool-1-thread-4执行完了
pool-1-thread-5执行完了
pool-1-thread-6执行完了
pool-1-thread-7执行完了
pool-1-thread-8执行完了
pool-1-thread-9执行完了
pool-1-thread-10执行完了

4. 提供了“延迟”和“周期执行”功能的ThreadPoolExecutor。

public ScheduledThreadPoolExecutor(int corePoolSize) {super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,new DelayedWorkQueue());
}
public ScheduledThreadPoolExecutor(int corePoolSize,ThreadFactory threadFactory) {super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue(), threadFactory);
}
public ScheduledThreadPoolExecutor(int corePoolSize,RejectedExecutionHandler handler) {super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue(), handler);
}
public ScheduledThreadPoolExecutor(int corePoolSize,ThreadFactory threadFactory,RejectedExecutionHandler handler) {super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue(), threadFactory, handler);
}

举例

import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;public class ScheduledThreadPoolCase {static class Task implements Runnable {@Overridepublic void run() {try {String name = Thread.currentThread().getName();System.out.println(name + ", 开始:" + new Date());Thread.sleep(1000);System.out.println(name + ", 结束:" + new Date());} catch (InterruptedException e) {e.printStackTrace();}}}public static void main(String[] args) throws InterruptedException {//按照周期执行的线程池,核心线程数为2,最大线程数为Integer.MAX_VALUEScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(2);System.out.println("程序开始:" + new Date());/*** schedule 提交任务到线程池中* 第一个参数:提交的任务* 第二个参数:任务执行的延迟时间* 第三个参数:时间单位*/scheduledThreadPool.schedule(new Task(), 0, TimeUnit.SECONDS);scheduledThreadPool.schedule(new Task(), 1, TimeUnit.SECONDS);scheduledThreadPool.schedule(new Task(), 5, TimeUnit.SECONDS);Thread.sleep(5000);// 关闭线程池scheduledThreadPool.shutdown();}}

运行结果:

程序开始:Mon Apr 29 22:26:18 CST 2024
pool-1-thread-1, 开始:Mon Apr 29 22:26:18 CST 2024
pool-1-thread-2, 开始:Mon Apr 29 22:26:19 CST 2024
pool-1-thread-1, 结束:Mon Apr 29 22:26:19 CST 2024
pool-1-thread-2, 结束:Mon Apr 29 22:26:20 CST 2024
pool-1-thread-1, 开始:Mon Apr 29 22:26:23 CST 2024
pool-1-thread-1, 结束:Mon Apr 29 22:26:24 CST 2024

综上:
newFixedThreadPool:创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待
newSingleThreadExecutor:创建一个单线程化的线程池,它只会用唯一的工作线程来执行任 务,保证所有任务按照指定顺序(FIFO)执行
newCachedThreadPool:创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程
newScheduledThreadPool:可以执行延迟任务的线程池,支持定时及周期性任务执行

为什么不使用Excutors创建线程池

参考阿里开发手册《Java开发手册-嵩山版》
在这里插入图片描述
ps:OOM是指内存溢出。
最后,建议根据计算机的条件使用ThreadPoolExecutor创建线程池(突然感觉上一节白学了,唉~)。

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

【matplot】【matlab】绘制简洁美观二维坐标系的一个例子

觉得下图不错美观大方&#xff0c;现仿制下图&#xff1a; import numpy as np import matplotlib.pyplot as pltdef sigmoid(x):return 1 / (1 np.exp(-x))def sigmoid_derivative(x):return sigmoid(x) * (1 - sigmoid(x))# 设置中文字体 plt.rcParams[font.family] [Tim…

1-手工sql注入(基础篇)

关于靶场: 本章使用的靶场是pikachu和dvwa&#xff1a;针对于pikachu靶场上的sql注入pikachu和dvwa靶场下载地址&#xff1a;GitHub - digininja/DVWA: Damn Vulnerable Web Application (DVWA)GitHub - zhuifengshaonianhanlu/pikachu: 一个好玩的Web安全-漏洞测试平台 一. sq…

numpy+matplotlib绘制玫瑰线图案

【第10次课]实验十一数据可视化及应用】 声明&#xff1a;著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。 1.简答题 本实验绘制简单图形&#xff0c;要导入numpy库函数和matplotlib.pyplot子库函数: import matplotlib.pyplot as plt impor…

Leetcode—1329. 将矩阵按对角线排序【中等】(unordered_map、priority_queue)

2024每日刷题&#xff08;121&#xff09; Leetcode—1329. 将矩阵按对角线排序 实现代码 class Solution { public:vector<vector<int>> diagonalSort(vector<vector<int>>& mat) {const int m mat.size();const int n mat[0].size();unorder…

OpenLayers入门①(引入的是一个高德地图)

OpenLayers入门&#xff08;一&#xff09; - 知乎 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport&qu…

【百度Apollo】探索自动驾驶:小白教学如何使用 Dreamview 播放数据包

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《linux深造日志》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 引入一、Dreamview 简介二、使用 Dreamview 具体步骤步骤一&#xff1a;进入 Apollo Docker 环境步骤二&#xff…

HaLo-NeRF:利用视觉和语言模型对场景的精准定位和细粒度语义理解

包含大量摄影师拍摄的照片的互联网图像集有望实现对大型旅游地标的数字探索。然而&#xff0c;先前的工作主要集中在几何重建和可视化上&#xff0c;忽略了语言在为导航和细粒度理解提供语义界面方面的关键作用。 项目&#xff1a;HaLo-NeRF: Learning Geometry-Guided Semant…

Vue+Element UI el-progress进度条内显示自定义数字及文字

需求 进度条内展示 具体的数字值&#xff0c;进度条外展示 百分比数值 数据 data() {return {reNum: 3214,rePer:40,warmPer: 40,warmNum:2132,}}因为样式要求&#xff0c;显示的百分数也是自己写的哈 &#xff0c;没有用进度条自带的 代码 <div class"pick"&g…

基于Sping Boot集成的websocket实现聊天室

Spring Boot整合WebSocket实现聊天室 Spring Boot 提供了 Websocket 组件 spring-boot-starter-websocket&#xff0c;用来支持在 Spring Boot环境下对Websocket 的使用。 下面我们就以多人在线聊天室为例&#xff0c;演示 Spring Boot 是如何整合Websocket 实现服务端消息推…

pkpmbs 建设工程质量监督系统 Ajax_operaFile.aspx 文件读取漏洞复现

0x01 产品简介 pkpmbs 建设工程质量监督系统是湖南建研信息技术股份有限公司一个与工程质量检测管理系统相结合的,B/S架构的检测信息监管系统。 0x02 漏洞概述 pkpmbs 建设工程质量监督系统 Ajax_operaFile.aspx接口处存在文件读取漏洞,未经身份认证的攻击者可以利用漏洞读…

【yolov8目标检测部署】TensorRT int8量化

原作者github&#xff1a;https://github.com/xuanandsix/Tensorrt-int8-quantization-pipline/tree/main 改进&#xff1a; 源代码支持的TensorRT版本为7.许多属性已经弃用&#xff1b; 在原有的代码上将支持的TensorRT版本从7改到8. &#xff01;&#xff01;不知道如何安装T…

记录k8s以docker方式安装Kuboard v3 过程

原本是想通过在k8s集群中安装kuboad v3的方式安装kuboard&#xff0c;无奈在安装过程中遇到了太多的问题&#xff0c;最后选择了直接采用docker安装的方式&#xff0c;后续有时间会补上直接采用k8s安装kuboard v3的教程。 1.kuboard安装文档地址&#xff1a; 安装 Kuboard v3 …

[C++][数据结构]二叉搜索树:介绍和实现

二叉搜索树 概念 二叉搜索树又称二叉排序树&#xff0c;它是一棵空树&#xff0c;或者是具有以下性质的二叉树: 若它的左子树不为空&#xff0c;则左子树上所有节点的值都小于根节点的值若它的右子树不为空&#xff0c;则右子树上所有节点的值都大于根节点的值它的左右子树也…

使用STM32CubeMX对STM32F4进行串口配置

目录 1. 配置1.1 Pin脚1.2 RCC开启外部晶振1.3 时钟1.4 串口配置 2. 代码2.1 默认生成代码2.1 开启串口中断函数2.3 接收中断2.4 接收回调函数2.5 增加Printf 的使用 1. 配置 1.1 Pin脚 1.2 RCC开启外部晶振 1.3 时钟 外部使用8MHz晶振 开启内部16MHz晶振 使用锁相环 开启最高…

利用word2vec包将中文转变为词向量

代码展示&#xff1a; import jieba import re import json import logging import sys import gensim.models as word2vec from gensim.models.word2vec import LineSentence, loggerpattern u[\\s\\d,.<>/?:;\\"[\\]{}()\\|~!\t"#$%^&*\\-_a-zA-Z&…

机器学习:基于Sklearn、XGBoost框架,使用逻辑回归、支持向量机和XGBClassifier来诊断并预测一个人是否患有自闭症

前言 系列专栏&#xff1a;机器学习&#xff1a;高级应用与实践【项目实战100】【2024】✨︎ 在本专栏中不仅包含一些适合初学者的最新机器学习项目&#xff0c;每个项目都处理一组不同的问题&#xff0c;包括监督和无监督学习、分类、回归和聚类&#xff0c;而且涉及创建深度学…

【Java--数据结构】链表经典OJ题详解(下)

前言 上一篇 欢迎关注个人主页&#xff1a;逸狼 创造不易&#xff0c;可以点点赞吗~ 如有错误&#xff0c;欢迎指出~ 目录 前言 链表分割 链表的回文结构 相交链表 环形链表 链表分割 编写代码&#xff0c;以给定值x为基准将链表分割成两部分&#xff0c;所有小于x的结点排在…

Microsoft Threat Modeling Tool 使用(二)

主界面 翻译 详细描述 选择了 “SDL TM Knowledge Base (Core)” 模板并打开了一个新的威胁模型。这个界面主要用于绘制数据流图&#xff08;Data Flow Diagram, DFD&#xff09;&#xff0c;它帮助您可视化系统的组成部分和它们之间的交互。以下是界面中各个部分的功能介绍&a…

深度学习 --- stanford cs231学习笔记(一)

stanford cs231学习笔记(一) 1&#xff0c;先是讲到了机器学习中的kNN算法&#xff0c;然后因为kNN分类器的一些弊端&#xff0c;引入了线性分类器。 kNN算法的三大弊端&#xff1a; (1)&#xff0c;计算量大&#xff0c;当特征比较多时表示性差 (2)&#xff0c;训练时耗时少…

[python数据处理系列] 深入理解与实践基于聚类的过采样与欠采样技术:以K-Means为例

目录 一、过采样介绍 (一)什么是过采样 (二)过采样的优点 (三)过采样的缺点 二、欠采样介绍 (一)什么是欠采样 (二)欠采样的优点 (三)欠采样的缺点 三、基于聚类的欠抽样方法(K-Means欠采样/KMeans-Undersampling) (一)KMeans欠采样原理及其步骤介绍 (二)为什么不采…