JAVA面经整理(5)

创建线程池不是说现用先创建,而是要是可以复用线程池中的线程,就很好地避免了大量用户态和内核态的交互,不需要频繁的创建和销毁线程

一)什么是池化技术?什么是线程池? 

1)池化技术是提前准备好一些资源,在需要的时候可以重复使用这些准备好的资源,池化技术的优点主要有两个:提前使用和重复利用

2)线程池会先启动若干数量的线程,这些线程都会处于睡眠状态,当有一个新的任务到来的时候,线程池就会唤醒某一个睡眠的线程,让他来进行处理客户端的请求,当处理完整个请求之后,线程又处于睡眠的状态,线程池可以很好地提高程序执行的性能,因为频繁的创建和销毁线程是很浪费时间的;

3)现在假设有一个大型的网络中心,高峰期每一秒的客户端请求的并发数超过100,如果为每一个客户端都创建一个线程,那么耗费的CPU资源和内存资源都是非常惊人的,假设如果现在拥有一个数量是200的线程池,那么将会节约大量的系统资源和内存资源,使得有更多的CPU资源和内存资源来处理实际的业务,而不是把这些资源放在创建和销毁线程上;

1)复用线程:降低资源消耗

咱们的线程创建是需要开辟虚拟机栈,本地方法栈,程序计数器等一些私有的线程的内存空间,而销毁的时候又要回收这些私有空间资源,线程就可以重复的进行使用了,使得有更多的CPU资源和内存资源放在实际的业务处理上

2)提高响应速度

咱们的线程池使用已有线程来进行执行任务的,而线程当有人来的时候,现使用现创建,涉及到大量用户态和内核态的交互,所以说线程池可以更快的响应,就已经有PCB了;

3)管理线程数和任务数:线程池提供了更多的管理功能

3.1)控制最大并发数:控制最大并发线程数,线程池可以创建固定的线程数,从而避免了无限创建线程的问题,当线程创建过多的时候,会出现系统执行变慢,因为CPU核数是固定的,能够处理的任务数量也是一定的,但是当线程过多的时候,就会造成线程恶意争抢和线程频繁切换的问题,从而导致程序执行效率变慢,所以合适数量的线程才是高性能运行的关键

3.2)控制任务最大数:如果任务无限多,而内存又不足,就会导致程序执行报错,所以我们采用拒绝策略来进行处理多出的任务,从而保证系统可以健康的运行;

4)提供定期执行的功能

其他的常见的池化技术:

1)内存池:

1.1)内存池在进行创建的过程中,首先在程序启动的过程中,会向操作系统申请一大块内存

1.2)然后每次用户请求内存的时候,就会返回内存池中的一块空闲的内存,并将这块内存的标志置为true,标记为已经使用;

1.3)当内存使用完毕释放内存的时候,也不是真正地调用 free 或 delete 的过程,而是把内存放回内存池的过程,且放回的过程要把标志置为false;

1.4)最后,应用程序结束就会将内存池销毁,将内存池中的每一块内存释放

优点:减少了内存碎片的产生,提高了内存的使用频率

缺点:会造成内存的浪费,因为要使用内存池需要在一开始分配一大块闲置的内存,而这些内存不一定全部被用到

2)数据库连接池:

2.1)数据库连接池的基本思想是在系统初始化的时候将数据库连接作为对象存储在内存中,当用户需要访问数据库的时候,并非建立一个新的连接,而是从连接池中取出一个已建立的空闲连接对象;

2.2)在使用完毕后,用户也不是将连接关闭,而是将连接放回到连接池中,以供下一个请求访问使用,而这些连接的建立、断开都是由连接池自身来管理的

2.3)同时还可以设置连接池的参数来控制连接池中的初始连接数、连接的上下限数和每个连接的最大使用次数、最大空闲时间等。当然,也可以通过连接池自身的管理机制来监视连接的数量、使用情况等

二)谈谈线程池的参数:

1)这个核心线程数如果设置成0,那么表示没有任务的时候销毁线程池,如果核心线程数大于0表示线程池即使没有任务的时候最少的线程池的数量等于这个值,如果设置比较小,那么会频繁的创建和销毁线程,如果创建的值比较大,那么会浪费大量的系统资源
2)如果线程池空闲的时间超过了此时间,那么多余的线程就会被销毁,直到线程池中的线程的销毁数量等于corepoolsize,如果本身corepoolsize等于maxmunsize,那么线程池在空闲的时候也不会销毁任何线程

三)如何设置corePoolsize maximumpoolsize之间的关系呢?

1)如果解决的任务和任务量比较稳定,我们会把corePoolsize和maximumpoolsize

之间的关系设得会比较接近,让临时工尽量少一些;

2)但是如果解决的任务场景,任务量波动比较大,可以让corePoolsize和maximumpoolsize之间的差值大一些,多多的进行招临时工,让临时工的数量多一些;

3)这个题太开放了,和机器,执行任务的类型有关,还是要通过实验来进行,从节省资源和执行效率的角度进行权衡,通过实验的方式来进行测试比较合适;

4)为什么线程池里面还要销毁线程?

1)这是在性能和资源之间在做平衡,线程完全不销毁,相当于是性能最大化,创建线程销毁线程的次数最少,但是吃的资源也是最多的,尤其是内存资源;

2)线程不消毁,线程越多,只是把性能跳到了最大限度,但是这些线程也会占用一定的资源,如果任务量更少,进程不干活,拜拜,把内存资源节省出来给其他工作去使用

3)其中的keepAlivetime,的时间越短,希望吃的资源越少,时间越短,就可以更快地释放资源,临时工线程就可以早早得进行走人,线程就可以及时地释放,把系统资源让出来;

进行使用多线程,不就是说为了让程序跑得更快吗?但是咱们为啥不让CPU占用率太高呢?

对于线上服务器来说,要对CPU资源留有一定的冗余,随时应对一些可能的突发情况,如果说请求已经本身已经快把CPU占用完了,这个时候突然来了一波请求的峰值,请求暴涨,此时我们的服务器很有可能就会挂

5)如何设置线程池中线程的个数? 

有一个程序,这个程序要进行并发的,多线程来进行处理一些任务,如果使用线程池的话,这里面的线程数我们进行设置成多少是比较合适的呢?

1)针对这个问题,不能给出一个具体的值,只要是能够回答出一个具体的数字,那么一定是错误的

2)我们只能通过一系列的方法来找到一个具体的值,而不是说直接再进行测试之前,就直接进行拍板子一定就行的

正确的方式:要通过性能测试的方式,来找到合适的值

1)比如说可以写一个服务器程序,服务器里面通过线程池,多线程的处理用户请求

我们就可以针对这个服务器进行性能测试,比如说构造一些请求,发送给服务器,因为是要要进行测试性能,所以这里面的构造请求就需要构造很多,比如说每秒构造500/1000/2000请求,根据实际的业务场景,来进行构建一个合适的值;

2)我们再进行性能测试的时候,我们就可以根据不同的线程池中的线程数,来进行观察两个指标,程序处理任务的速度,程序持有的CPU的占用率

2.1)当我们的线程数多了,整体的速度会变快,但是CPU的占用率也会变高

2.2)当我们的线程数少了,整体的速度会变慢,但是CPU的占有率也会下降

我们需要在合适的情况下找到一个平衡点,所以说应该需要找到一个让程序速度可以接受,并且CPU占用也合理的这样一个平衡点,这才是我们正确的做法

2.2)因为不同类型的程序,因为单个任务,里面CPU的计算的时间和阻塞的时间分布是不相同的,因此光去拍脑门进行设置是不可以的,一定要进行性能测试

6)在JAVA中创建线程池有哪几种方式? 

大体上创建线程池一共有两种方式,要么通过ThreadPoolExcutor创建线程池,要么通过Excutors执行器创建线程池

1)Executors.newFixedThreadPool:创建一个固定数量的线程池,可控制并发的线程数,超出的任务会在队列中等待,建出一个固定线程数量的线程池,完全没有零时工的版本,参数指定了线程的个数

  //1.创建一个固定大小的线程池,可以控制并发线程数ExecutorService threadPool= Executors.newFixedThreadPool(2);Runnable runnable=new Runnable() {@Overridepublic void run() {System.out.println("任务被执行"+Thread.currentThread().getName());}};threadPool.submit(runnable);threadPool.submit(runnable);threadPool.submit(runnable);threadPool.submit(runnable);
//打印结果:
任务被执行pool-1-thread-2
任务被执行pool-1-thread-1
任务被执行pool-1-thread-2
任务被执行pool-1-thread-1
//先执行两个任务,剩余的任务直接进行排队执行

2)Exectors.newCatchedThreadPool:创建出了一个数量可变的线程池,完全没有正式员工,全是临时工,是一个自动扩容的线程池,会根据任务量来自动进行扩容,如果线程数超过处理所需,那么多余的线程会进行缓存一会被回收,如果线程数不够就新创建线程

创建出了一个数量可变的线程池,完全没有正式员工,全是临时工,是一个自动扩容的线程池,会根据短时间内的任务量来自动进行扩容,适合短时间内有大量突发任务的场景

package OperateNode;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ExectorOperator {public static void main(String[] args) {ExecutorService service=Executors.newCachedThreadPool();for(int i=0;i<10;i++){service.submit(new Runnable() {@Overridepublic void run() {System.out.println("线程池正在创建任务"+Thread.currentThread().getName());}});}}
}
打印结果:
线程池正在创建任务pool-1-thread-2
线程池正在创建任务pool-1-thread-1
线程池正在创建任务pool-1-thread-4
线程池正在创建任务pool-1-thread-3
线程池正在创建任务pool-1-thread-7
线程池正在创建任务pool-1-thread-5
线程池正在创建任务pool-1-thread-9
线程池正在创建任务pool-1-thread-6
线程池正在创建任务pool-1-thread-10
线程池正在创建任务pool-1-thread-8
从上面可以看出线程池创建了10个线程来进行执行相应的任务

3)ScheduleExecutorServiceservice=Exectors.ScheduledThreadPool

newScheduleThreadPool:能够设定延长时间的线程池,插入的任务能够过一会再执行,相当于进阶版的定时器,带有定时器功能的线程池;

   ScheduledExecutorService service=Executors.newScheduledThreadPool(5);//添加定时任务1s后执行System.out.println(new Timestamp(System.currentTimeMillis()));service.schedule(new Runnable() {@Overridepublic void run() {System.out.println("我是大佬");}},1,TimeUnit.SECONDS);System.out.println(new Timestamp(System.currentTimeMillis()));}
}

4)Exectors.newSingleThreadScheduledExector

创建一个单线程并且可以执行延迟任务的线程池;

  ScheduledExecutorService service =Executors.newSingleThreadScheduledExecutor();service.schedule(new Runnable() {@Overridepublic void run() {System.out.println("大佬");}},2, TimeUnit.SECONDS);}

5)Exectors.newSingleThreadExecutor:创建一个单个线程数的线程池,拥有任务队列,保证任务先进先出的执行顺序

package OperateNode;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;public class ExectorOperator {public static void main(String[] args) {ExecutorService service= Executors.newSingleThreadExecutor();for(int i=0;i<10;i++){final int index=i;service.submit(new Runnable() {@Overridepublic void run() {System.out.println("当前任务"+index+"正在被执行"+Thread.currentThread().getName());try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}}});}}
}
打印结果为:
当前任务0正在被执行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
public static void main(String[] args) {ExecutorService service= Executors.newSingleThreadExecutor();for(int i=0;i<10;i++){final int index=i;service.submit(new Runnable() {@Overridepublic void run() {System.out.println("当前线程池正在运行第"+index+"个任务");try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}}});}}
}

那么单个线程的线程池有什么意义呢?

1)可以进行复用线程,即使是单个线程池也可以进行复用线程

2)提供了任务管理功能,单个线程池也有任务队列,在任务队列可以进行存储多个任务,并且当任务队列满了之后,保证任务顺序执行,可以执行拒绝策略,这些都是线程所不会具备的;

6)创建一个抢占式执行的线程池:Exectors.newWorkStealingPool:创建一个抢占式执行的线程池,就是任务执行顺序不确定,在JDK1.8中才可以进行使用

public class ExectorOperator {public static void main(String[] args) {ExecutorService service=Executors.newWorkStealingPool();//下面是执行流程for(int i=0;i<10;i++){final int index=i;service.submit(new Runnable() {@Overridepublic void run() {System.out.println(index+"被"+Thread.currentThread().getName()+"执行");}});}while(!service.isTerminated()){
//确保任务完成}}}
7)为什么创建线程池一定要使用ThreadPoolExecutor?

ThreadPool是最原始也是最推荐的手动创建线程池的方式,可以通过参数来进行控制最大任务数和最大线程数和拒绝策略,让线程池的执行更加透明和可控,明确线程池的运行规则,规避资源耗尽的风险

1)FixedThreadPool 和 SingleThreadPool:允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM

2)CachedThreadPool:允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM

8)手动创建线程池
9)谈谈工厂模式: 

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

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

相关文章

[React] 性能优化相关 (一)

文章目录 1.React.memo2.useMemo3.useCallback4.useTransition5.useDeferredValue 1.React.memo 当父组件被重新渲染的时候&#xff0c;也会触发子组件的重新渲染&#xff0c;这样就多出了无意义的性能开销。如果子组件的状态没有发生变化&#xff0c;则子组件是不需要被重新渲…

华为智能企业上网行为管理安全解决方案(1)

华为智能企业上网行为管理安全解决方案&#xff08;1&#xff09; 课程地址方案背景需求分析企业上网行为概述企业上网行为安全风险分析企业上网行为管理需求分析 方案设计组网架构设备选型设备简介行为管理要点分析方案功能概述 课程地址 本方案相关课程资源已在华为O3社区发…

网络协议--概述

1.2 分层 网络协议通常分不同层次进行开发&#xff0c;每一层分别负责不同的通信功能。一个协议族&#xff0c;比如TCP/IP&#xff0c;是一组不同层次上的多个协议的组合。TCP/IP通常被认为是一个四层协议系统&#xff0c;如图1-1所示。 每一层负责不同的功能&#xff1a; 1.…

C++(string类)

本节目标&#xff1a; 1、为什么要学习string类 2.标准库中的string类 3.vs和g下string结构说明 1.为什么学习string类 1.1 c语言中的字符串 C 语言中&#xff0c;字符串是以 \0 结尾的一些字符的集合&#xff0c;为了操作方便&#xff0c; C 标准库中提供了一些 str系列的…

基于java的鲜花销售系统/网上花店

摘 要 本毕业设计的内容是设计并且实现一个基于Spring Boot框架的驿城鲜花销售系统。它是在Windows下&#xff0c;以MYSQL为数据库开发平台&#xff0c;Tomcat网络信息服务作为应用服务器。驿城鲜花销售系统的功能已基本实现&#xff0c;主要包括首页、个人中心、用户管理、鲜…

【算法挨揍日记】day10——704. 二分查找、34. 在排序数组中查找元素的第一个和最后一个位置

704. 二分查找 704. 二分查找 题目描述&#xff1a; 给定一个 n 个元素有序的&#xff08;升序&#xff09;整型数组 nums 和一个目标值 target &#xff0c;写一个函数搜索 nums 中的 target&#xff0c;如果目标值存在返回下标&#xff0c;否则返回 -1。 解题思路&…

【VIM】初步认识VIM-2

2-6 Vim 如何搜索替换_哔哩哔哩_bilibili 1-6行将self改成this 精确替换quack单词为交

linux系统与应用

Windows中的硬盘和盘符的关系&#xff1b; 硬盘通常为一块到两块&#xff1b;数量与盘符没有直接关系&#xff1b;一块硬盘可以分为多个盘符&#xff0c;如c,d,e,f,g等&#xff1b;当然理论上也可以一块硬盘只有一个盘符&#xff1b;学习linux时&#xff0c;最好使用固态硬盘&a…

如何使用jenkins、ant、selenium、testng搭建自动化测试框架

如果在你的理解中自动化测试就是在eclipse里面讲webdriver的包引入&#xff0c;然后写一些测试脚本&#xff0c;这就是你所说的自动化测试&#xff0c;其实这个还不能算是真正的自动化测试&#xff0c;你见过每次需要运行的时候还需要打开eclipse然后去选择运行文件吗&#xff…

毕业设计选题uniapp+springboot新闻资讯小程序源码 开题 lw 调试

&#x1f495;&#x1f495;作者&#xff1a;计算机源码社 &#x1f495;&#x1f495;个人简介&#xff1a;本人七年开发经验&#xff0c;擅长Java、Python、PHP、.NET、微信小程序、爬虫、大数据等&#xff0c;大家有这一块的问题可以一起交流&#xff01; &#x1f495;&…

JavaScript——APIs

复习&#xff1a; splice() 方法用于添加或删除数组中的元素。 **注意&#xff1a;**这种方法会改变原始数组。 删除数组&#xff1a; splice(起始位置&#xff0c; 删除的个数) 比如&#xff1a;1 let arr [red, green, blue] arr.splice(1,1) // 删除green元素 consol…

助力交叉学科应用型数据科学人才培养,和鲸科技携手华为发布联合解决方案

时代高速发展&#xff0c;智能化的浪潮奔腾而来&#xff0c;以“加速行业智能化”为主题&#xff0c;第八届华为全联接大会&#xff08;HUAWEI CONNECT 2023&#xff09;于 9 月 20 日正式开幕。本次大会中&#xff0c;华为携手生态伙伴引领智慧教育新风尚&#xff0c;和鲸科技…

新闻报道的未来:自动化新闻生成与爬虫技术

概述 自动化新闻生成是一种利用自然语言处理和机器学习技术&#xff0c;从结构化数据中提取信息并生成新闻文章的方法。它可以实现大规模、高效、多样的新闻内容生产。然而&#xff0c;要实现自动化新闻生成&#xff0c;首先需要获取可靠的数据源。这就需要使用爬虫技术&#…

设计一个简单的通讯录

目录 导读&#xff1a; 一、主函数 1. 打印功能菜单 2. 用枚举常量列举功能给功能赋值&#xff08;0-5&#xff09; 3. main主函数 二、头文件 三、通讯录各功能的实现 1. 初始化通讯录 2. 增加联系人 3. 展示所有联系人信息 4. 删除指定联系人 5. 查询指定联系人…

Redis入门到精通——00数据类型

1、String 1.1、介绍 String 是最基本的 key-value 结构&#xff0c;key 是唯一标识&#xff0c;value 是具体的值&#xff0c;value其实不仅是字符串&#xff0c; 也可以是数字&#xff08;整数或浮点数&#xff09;&#xff0c;value 最多可以容纳的数据长度是 512M 1.2、…

【Django】4 Django模型

每个模型是一个Python 类&#xff0c;集成django.db.models.Modle类 该模型的每个属性表示一个数据库表字段 通过API 自动生成数据库访问 .../sign/modles.py 文件&#xff0c;通过模型完成表创建。 TypeError: ForeignKey.__init__() missing 1 required positional argumen…

【算法训练-贪心算法】一 买卖股票的最佳时机II

废话不多说&#xff0c;喊一句号子鼓励自己&#xff1a;程序员永不失业&#xff0c;程序员走向架构&#xff01;本篇Blog的主题是【贪心算法】&#xff0c;使用【数组】这个基本的数据结构来实现&#xff0c;这个高频题的站点是&#xff1a;CodeTop&#xff0c;筛选条件为&…

【小沐学前端】Node.js实现基于Protobuf协议的UDP通信(UDP/TCP)

文章目录 1、简介1.1 node1.2 Protobuf 2、下载和安装2.1 node2.2 Protobuf2.2.1 安装2.2.2 工具 3、node 代码示例3.1 HTTP3.2 UDP单播3.4 UDP广播 4、Protobuf 代码示例4.1 例子: awesome.proto4.1.1 加载.proto文件方式4.1.2 加载.json文件方式4.1.3 加载.js文件方式 4.2 例…

idea Springboot在线商城系统VS开发mysql数据库web结构java编程计算机网页源码maven项目

一、源码特点 springboot 在线商城系统是一套完善的信息系统&#xff0c;结合springboot框架和bootstrap完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用springboot框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统具有 完整的源代码和数据库&…

多目标平衡优化器黏菌算法(MOEOSMA)求解CEC2020多模式多目标优化

多目标平衡优化器黏菌算法&#xff08;MOEOSMA&#xff09;比现有的多目标黏菌算法具有更好的优化性能。在MOEOSMA中&#xff0c;动态系数用于调整勘探和开采趋势。采用精英存档机制来促进算法的收敛性。使用拥挤距离法来保持Pareto前沿的分布。采用平衡池策略模拟黏菌的协同觅…