【Java面试】十九、并发篇(下):线程池

news2024/11/28 7:44:56

文章目录

  • 1、为什么要使用线程池
  • 2、线程池的执行原理
    • 2.1 七个核心参数
    • 2.2 线程池的执行原理
  • 3、线程池用到的常见的阻塞队列有哪些
  • 4、如何确定核心线程数开多少个?
  • 5、线程池的种类有哪些?
  • 6、为什么不建议用Executors封装好的静态方法创建线程池
  • 7、线程池的使用场景
  • 8、如何控制某个方法运行并发访问线程的数量
  • 9、ThreadLocal相关
    • 9.1 理解
    • 9.2 ThreadLocal的内存泄露问题

1、为什么要使用线程池

  • 降低资源消耗:降低避免频繁创建和销毁线程的代价
  • 提高响应速度:任务达到时,不用再等待创建线程
  • 线程管理方便:线程过多,调度开销大,用线程池可防止过分调度,且可以做统一的监控、分配、调优

此外,还有:

  • 每次创建线程,都要占用一定的内存空间,如果无限制的创建线程,会浪费内存
  • 一核的CPU,同一时刻只能处理一个线程,如果大量请求一来就创建对应数量的线程,那很多线程也没有CPU时间片,只能阻塞,还会导致线程之间频繁切换

2、线程池的执行原理

2.1 七个核心参数

以银行为例对比:银行大厅一共有10个窗口(最大线程数量),但平时一般只开5个(常驻线程数量),某天办理业务的人很多,5个窗口不够用,其余人来了就先在大厅椅子上坐着等(阻塞队列),结果椅子坐满了,还有人陆续来,于是10个窗口全开,还来很多人,那就只能告诉新来的今天轮不到你办了(拒绝策略)。

在这里插入图片描述

解释:

  • corePoolSize:核心线程数目
  • maximumPoolSize:最大线程数目 = 核心线程+ 救急线程的最大数目
  • keepAliveTime:救急线程的生存时间,没有活跃的任务给救急线程处理了,超过了生存时间就会释放
  • unit:救急线程的生存时间单位
  • workQueue:当没有空闲核心线程时,新来任务会加入到此队列排队,队列满会创建救急线程执行任务(阻塞队列)
  • threadFactory:线程工厂,定制线程对象的创建,如设置线程名字、是否是守护线程
  • handler:拒绝策略 ,当所有线程都在繁忙, workQueue 也放满时,会触发拒绝策略

2.2 线程池的执行原理

提交一个任务到线程池以后:先判断核心线程数是否满了,否则直接让核心线程去执行,反之继续判断阻塞队列是否已满,没满就扔阻塞队列,满了就看线程数是否超过总数,没超,说明还有应急线程可用,反之则走拒绝策略:

  • AbortPolicy:直接抛出异常,默认策略
  • CallerRunsPolicy:用调用者所在的线程来执行任务,如main线程
  • DiscardOldestPolicy:丢弃阻塞队列中靠最前的任务,并执行当前任务
  • DiscardPolicy:直接丢弃当前任务,不抛异常

注意,救急线程(或者叫临时线程、非核心线程)执行完手里的任务后,会检查阻塞队列中是否有需要执行的线程,有则继续干。对于核心线程,正式工,它们一直存在,自然更要检查阻塞队列,然后继续干队列里的活儿。

在这里插入图片描述

3、线程池用到的常见的阻塞队列有哪些

【阻塞队列】

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

  • ArrayBlockingQueue:基于数组结构的有界阻塞队列,FIFO
  • LinkedBlockingQueue:基于链表结构的有界阻塞队列(长度默认Int的最大值),FIFO
  • DelayedWorkQueue :是一个优先级队列,它可以保证每次出队的任务都是当前队列中执行时间最靠前
  • SynchronousQueue:不存储元素的阻塞队列,每个插入操作都必须等待一个移出操作

LinkedBlockingQueue最为常用:

在这里插入图片描述

关于两把锁和一把锁:每个提交的任务封装成一个Node对象放进阻塞队列时,LinkedBlockingQueue 使用了两个锁,一个是 takeLock 用于控制出队操作,另一个是 putLock 用于控制入队操作。ArrayBlockingQueue则出队和入队都是同一把锁。

在这里插入图片描述

最后,PS:

线程池的阻塞队列中存储的是任务对象(实现了 Runnable 或 Callable 接口的实例),线程池中的工作线程不断从阻塞队列中取出任务并执行

4、如何确定核心线程数开多少个?

假设N为CPU的核心数。

1)如果场景是高并发且任务执行时间短,核心线程数设置为N+ 1,减少线程上下文切换

2)如果是并发不高,且执行任务时间长,则:

  • 对于IO密集型任务,如文件读写、DB读写、网络请求,核心线程数设置为2N + 1
  • 对于CPU密集型任务,如计算型代码、Bitmap转换,核心线程数设置为N+ 1

因为对于IO密集的任务,其不耗费CPU,而偏计算型的任务(CPU密集型任务),设置为N + 1可以避免频繁切换CPU

在这里插入图片描述

最后,如果是并发高且每个业务执行时间也长,那这是优化重点就不是线程池了,而是整体架构,比如是否加入缓存,是否增加服务器,再看核心数是N+1 还是 2N+1

5、线程池的种类有哪些?

java.util.concurrent.Executors中提供了大量创建线程池的静态方法,常见的有:

1)固定线程数的线程池

在这里插入图片描述

  • 核心线程数与最大线程数相等,没有救急线程
  • 阻塞队列是 LinkedBlockingQueue,最大容量为int最大值

适用于任务量已知,相对耗时的任务

2)单线程的线程池

在这里插入图片描述

  • 核心线程数与最大线程数都是1,没有救急线程
  • 阻塞队列是 LinkedBlockingQueue,最大容量为int的最大值

只有一个线程,后面的请求过来,对应的线程进入阻塞队列,因此可以保证所有任务按顺序执行

3)可缓存的线程池

若线程池长度超过了处理需要,则灵活回收空闲线程,反之,则新建线程
在这里插入图片描述

  • 核心线程数为 0
  • 最大线程数为int的最大值
  • 阻塞队列为 SynchronousQueue,是一种不存储元素的阻塞队列,一个线程写入了数据,就必须得有一个线程取,否则不能再继续添加,用于传递性的场景

适合任务数比较密集,但每个任务执行时间较短的情况,否则会创建出大量线程

4)可执行延迟任务的线程池

源码:

在这里插入图片描述

如下,提交三个任务,分别延时0、1、5秒后可以从延迟队列中取到这个任务,然后从线程池分配个线程去执行

在这里插入图片描述

6、为什么不建议用Executors封装好的静态方法创建线程池

在这里插入图片描述

7、线程池的使用场景

单个任务处理时间比较短,但需要处理的任务的数量大。具体场景有:

  • 批量导入:如MySQL同步到ES。线程池 + CountDownLatch,分批导入Especially,防止OOM
  • 数据汇总:如资产全景、报表展示。调用多个接口汇总数据,且这些接口之间没有依赖关系,可用线程池 + future提高性能
  • 异步:如保存搜索记录,异步线程调用下一个方法,不影响上一级方法的性能

【以上三个使用场景的代码实现】

8、如何控制某个方法运行并发访问线程的数量

【JUC辅助类】

使用JUC辅助类Semaphore,维护一定数量的信号量,底层为AQS。常用于实现限流。

在这里插入图片描述

public class SemaphoreDemo {

    public static void main(String[] args) {
        //创建Semaphore,设置许可数量,三个车位,对应三个许可证
        Semaphore semaphore = new Semaphore(3);
        //模拟6辆汽车
        for (int i = 1; i <= 6; i++) {
            new Thread(() -> {
                try {
                    //抢占许可证
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName() + "抢到了车位");
                    //设置一个5s以内的随机时间,模拟停车
                    TimeUnit.SECONDS.sleep(new Random().nextInt(5));
                    System.out.println(Thread.currentThread().getName() + "=====> 离开了车位");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    //释放许可
                    semaphore.release();
                }
            },String.valueOf(i)).start();


        }
    }
}

在这里插入图片描述

和对象锁类似,不同的是,一个对象一把锁,而Semaphore可以自己指定信号量,一个信号量类似一把锁。

9、ThreadLocal相关

9.1 理解

成员变量,本来有线程安全问题,用ThreadLocal包装一下,则可实现每个线程都有自己的独立副本。 如用JDBC操作数据库时,会将各自的Connection对象用ThreadLocal包装,从而保证每个线程都在自己的Connection上操作数据库

在这里插入图片描述

ThreadLocal让每个线程只操作自己内部的值,从而实现线程数据隔离。ThreadLocal的结构如下,其有个内部类ThreadLocalMap,而ThreadLocalMap中有个table属性,是一个数组,数组里存着一个个的Entry对象。

在这里插入图片描述

而每个线程对象,又有ThreadLocal.ThreadLocalMap类型的属性,即每个线程对象,都有一个ThreadLocalMap对象。调用ThreadLocal的set、get、remove时,都是操作的当前线程的ThreadLocalMap的Entry类型的数组,这也是ThreadLocal对象实现线程隔离的关键,普通对象的set、get改的是普通对象自己,而ThreadLocal对象set、get改的当前线程对象的属性。

在这里插入图片描述

Thread、ThreadLocal、ThreadLocalMap的Entry数组,分别就像人、人的各种卡片(如身份证、学生证)、存各种卡片的卡包。每个人都有一个自己的卡包,卡包里装的卡片外形都一样(类比ThreadLcoal类型的成员变量),但卡片上面记录的信息是私有的,每个人的都不同(类比每个线程给ThreadLcoal类型的成员变量赋的值都不同)。

在这里插入图片描述
【ThreadLocal】

9.2 ThreadLocal的内存泄露问题

ThreadLocalMap 中的 key是弱引用,value 为强引用,key会被GC释放内存,关联 value的内存并不会释放,建议主动remove 释放 key,value

在这里插入图片描述

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

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

相关文章

虚拟化 之七 详解构造带有 jailhouse 的 openEuler 系统

构造一个默认带有 jailhouse 的 openEuler 系统实际上就是创建一个包含 jailhouse 软件包的 openEuler 发行版,创建的过程在 x86 和 嵌入式平台差距很大,因此,本文我们分别进行详细介绍。 x86_64 平台 对于 x86_64 平台,如果手动从头创建(参考 Linux From Scratch)一个自…

Kubernetes 集群架构

etcd 集群状态存储&#xff1a;etcd 存储所有 Kubernetes 对象的状态&#xff0c;例如部署、pod、服务、配置映射和机密。配置管理&#xff1a;集群配置的更改存储在 etcd 中&#xff0c;允许 Kubernetes 管理和维护集群的所需状态。 注意&#xff1a;etcd 可能位于 kube-syst…

【ARM Cache 与 MMU/MPU 系列文章 2.1 -- 什么是 Cache PoP 及 PoDP ?】

请阅读【ARM Cache 及 MMU/MPU 系列文章专栏导读】 及【嵌入式开发学习必备专栏】 文章目录 PoP 及 PoDPCache PoDPCache PoP应用和影响PoP 及 PoDP Cache PoDP 点对深度持久性(Point of Deep Persistence, PoDP)是内存系统中的一个点,在该点达到的任何写操作即使在系统供电…

git下载项目登录账号或密码填写错误不弹出登录框

错误描述 登录账号或密码填写错误不弹出登录框 二、解决办法 控制面板\用户帐户\凭据管理器 找到对应的登录地址进行更新或者删除 再次拉取或者更新就会提示输入登录信息

Linux服务器安装Jupyter,并设置公网访问详细教程

本章教程,主要介绍如何在Linux服务器上安装jupyter,并可以通过公网地址进行访问。 一、安装jupyter pip install jupyter二、生成jupyter配置文件 jupyter notebook --generate-config三、编辑这个配置文件 找到配置文件并修改以下配置项: # 允许所有 IP 地址访问 c.Noteb…

nodejs湖北省智慧乡村旅游平台-计算机毕业设计源码 00232

摘 要 随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;旅游行业当然也不能排除在外。智慧乡村旅游平台是以实际运用为开发背景&#xff0c;运用软件工程开发方法&#xff0c;采…

【ai】blender4.1 安装插件

开源软件,所以资料充足插件及配置 下载插件插件是python开发的 编辑中的偏好设置 点击选中 点击一键切换中文英文 切换主题 插件源码

卸载MySQL5.0,安装MySQL8.0

卸载MySQL 1、以管理员身份运行cmd,删除MySQL服务 2、卸载MySQL 3、删除残余文件 4、清楚注册表 winR -> regedit 5、删除环境变量 安装MySQL步骤 官方下载地址 https://www.mysql.com/downloads/ 以上步骤即完成MySQL数据库安装。

XSKY 在金融行业:新一代分布式核心信创存储解决方案

近日&#xff0c;国家金融监督管理总局印发了《关于银行业保险业做好金融“五篇大文章”的指导意见》&#xff0c;在数字金融领域提出明确目标&#xff0c;要求银行业保险业数字化转型成效明显&#xff0c;数字化经营管理体系基本建成&#xff0c;数字化服务广泛普及&#xff0…

SaaS企业营销:如何通过联盟计划实现销售增长?

联盟营销计划在国外saas行业非常盛行&#xff0c;国内如何借鉴国外的成功案例运用联盟计划实现销售增长呢&#xff1f;林叔今天以最近新发现的leadpages为例分享下经验。 Leadpages是一款用户友好的落地页制作工具&#xff0c;提供多种预设计模板、A/B测试和分析功能&#xff0…

【嵌入式DIY实例】-Nokia 5110显示DHT11/DHT22传感器数据

Nokia 5110显示DHT11/DHT22传感器数据 文章目录 Nokia 5110显示DHT11/DHT22传感器数据1、硬件准备2、代码实现2.1 显示DHT11数据2.2 显示DHT22数据本文介绍如何将 ESP8266 NodeMCU 开发板 (ESP-12E) 与 DHT11 数字湿度和温度传感器以及诺基亚 5110 LCD 连接。 NodeMCU 从 DHT11…

EMI电路

PFC 功率部分 1 、整流桥是串联 2 、 PFC 电感串联 3 、二极管并联 4 、 MOSFET 并联 EMI电路图

2024年山西泵管阀展览会11月8日开展

2024中国&#xff08;山西&#xff09;国际水务科技博览会 暨水处理技术设备与泵管阀展览会 时间&#xff1a;2024年11月8-10日 地点&#xff1a;山西潇河国际会展中心 经研究&#xff0c;由山西省水处理行业协会、山西省水暖阀门商会、山西省固废产业协会联合主办的2024…

SpringBoot+MyBatis批量插入数据的三种方式

文章目录 1. 背景介绍2. 方案介绍2.1 第一种方案&#xff0c;用 for语句循环插入&#xff08;不推荐&#xff09;2.2 第二种方案&#xff0c;利用mybatis的foreach来实现循环插入&#xff08;不推荐&#xff09;2.3 第三种方案&#xff0c;使用sqlSessionFactory实现批量插入&a…

3.00003 postmaster守护线程的启动流程调用以及辅助流程的启动流程调用是怎样的

文章目录 架构图相关数据结构child_process_kinds[]数组 (launch_backend.c:179)相关函数main.cPostmasterMain(postmaster.c:489)ServerLoop(postmaster.c:1624)BackendStartup(postmaster.c:3544)postmaster_child_launch (launch_backend.c:265)StartChildProcess (postma…

肾合能量不足?揭秘手心热出汗的真相

想象一下&#xff0c;我们的身体如同一座精密的城堡&#xff0c;城堡内的每一个房间都代表着一个器官&#xff0c;而城堡的守卫——气血&#xff0c;则是维系城堡和谐稳定的重要力量。当城堡中的守卫力量不足&#xff0c;或是城堡内的环境出现紊乱时&#xff0c;城堡的某个角落…

C# 生成解决方案时出现的一些异常及解决方法

一、ResolveAssemblyReference任务意外失败 在使用VS2022生成C#解决方案时&#xff0c;出现如下错误&#xff1a; 解决方法&#xff1a; 项目的依赖项出现问题&#xff0c;重新更新一下依赖项即可 二、生成Win32资源时出错 产生这个原因的主要原因是配置的应用程序的图标文…

计算机视觉全系列实战教程:(八)图像变换-点运算、灰度变换、直方图变换

图像变换&#xff1a;点运算、灰度变换、直方图变换 1.点运算(1)What(2)Why 2.灰度变换(1)What(2)Why(作用)(3)Which(有哪些灰度变换&#xff09; 3.直方图修正(1)直方图均衡化 1.点运算 (1)What 通过点运算&#xff0c;输出图像的每个像素的灰度值仅仅取决于输入图像中相对应…

AI预测体彩排3采取888=3策略+和值012路或双胆下一测试6月11日新模型预测第1弹

很抱歉各位小伙伴&#xff0c;端午节三天去了趟外地&#xff0c;没有按时更新3D和排三的预测。前面跟大家说过&#xff0c;8码定位是关键&#xff0c;8码定位能稳定在80%的命中率&#xff0c;才有望通过缩号缩至200-250注以内通过等额方式进行投资。由于前面的模型对8码定位的效…

家用洗地机怎么选?四大行业精品集合,识别度超高

家用洗地机&#xff0c;作为一种能够高效清洁地面的清洁工具&#xff0c;不仅减轻了人们家务的轻度&#xff0c;也给人们腾出了很多空闲的时间去享受生活。但是洗地机那么多&#xff0c;我们在面对洗地机选购的时候&#xff0c;我们应该要注意哪些呢&#xff1f;下面就为大家详…