JAVA面经整理(5)

news2024/11/25 18:46:08

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

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

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() {
            @Override
            public 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() {
              @Override
              public 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() {
            @Override
            public 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() {
            @Override
            public 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() {
                @Override
                public 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() {
                @Override
                public 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() {
                @Override
                public 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.coloradmin.cn/o/1056622.html

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

相关文章

PADS9.5使用记录

目录 一、概述 二、PADS Logic IN4148二极管封装 SOD-123封装 SOD-323封装 SOD-523封装 2N3904 1AM 三极管封装 78L05 7533-1 一、概述 PADS Logic 原理图绘制PADS Layout PCB 封装设计PADS Router 布线 二、PADS Logic …

【python学习第12节 pandas】

文章目录 一&#xff0c;pandas1.1 pd.Series1.2 pd.date_range1.3 pd_DataFrame1.4浏览数据1.5布尔索引1.6设置值1.7操作1.8合并1.8.1concat&#xff08;&#xff09;函数1.8.2 merge()函数 一&#xff0c;pandas 1.1 pd.Series pd.Series 是 Pandas 库中的一个数据结构&…

2023年【道路运输企业安全生产管理人员】最新解析及道路运输企业安全生产管理人员考试技巧

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 道路运输企业安全生产管理人员最新解析参考答案及道路运输企业安全生产管理人员考试试题解析是安全生产模拟考试一点通题库老师及道路运输企业安全生产管理人员操作证已考过的学员汇总&#xff0c;相对有效帮助道路运…

leetcode-239-滑动窗口最大值

题意描述&#xff1a; 给你一个整数数组 nums&#xff0c;有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回 滑动窗口中的最大值 。 示例&#xff1a; 输入&#xff1a;nums [1,3,-1,…

【C++】单例

设计一个类&#xff0c;只能在堆上创建对象 只能在堆上创建对象&#xff0c;也就是只能通过new操作符创建对象&#xff0c;方式如下&#xff1a; 将析构函数设为私有将释放空间的操作在类内保留一个接口&#xff0c;只能在类内进行调用将构造函数设置为私有&#xff0c;防止外…

计算机组成与结构

目录 一、计算机硬件组成 二、中央处理单元 1、功能 2、CPU的组成 三、校验码 四、体系结构的分类 1、按处理机数量分类 2、Flynn分类 五、指令系统 1、指令 2、寻址方式 3、指令系统 #CISC&#xff08;复杂指令集计算机&#xff09; RISC&#xff08;精简指令集…

阿里云关系型数据库有哪些?RDS云数据库汇总

阿里云RDS关系型数据库大全&#xff0c;关系型数据库包括MySQL版、PolarDB、PostgreSQL、SQL Server和MariaDB等&#xff0c;NoSQL数据库如Redis、Tair、Lindorm和MongoDB&#xff0c;阿里云百科分享阿里云RDS关系型数据库大全&#xff1a; 目录 阿里云RDS关系型数据库大全 …

图解大模型微调系列之:大模型低秩适配器LoRA(原理篇)

关于LORA部分的讲解&#xff0c;我们将分为**“原理篇”和“源码篇”**。 在原理篇中&#xff0c;我们将通过图解的方式&#xff0c;详细分析LoRA怎么用、为什么能奏效、存在哪些优劣势等核心问题。特别是当你在学习LoRA时&#xff0c;如果对“秩”的定义和作用方式感到迷惑&a…

基于Java的库存管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…

先做一年的弱电在做网络工程师这个顺序对不对

大家好&#xff0c;我是网络工程师成长日记实验室的郑老师&#xff0c;您现在正在查看的是网络工程师成长日记专栏&#xff0c;记录网络工程师日常生活的点点滴滴 有个同学说他原来是做视频审核的那个工作&#xff0c;我离职了&#xff0c;26岁他看了一些相关视频。他说他现在打…

电流流过电阻时会减小吗?

我相信很多人刚接触电路时都会有这个想法&#xff1a;由于电阻会抵抗或阻碍电荷的流动&#xff0c;假如现在电流往一个方向流动&#xff0c;且电路中只有一个电阻器&#xff0c;那么从电流流出的地方到刚接触电阻中间应该有有高电流&#xff0c;从电阻刚流出到最后应该有低电流…

SpringCloud Alibaba - Sentinel 高级玩法,修改 Sentinel-dashboard 源码,实现 push 模式

目录 一、规则持久化 1.1、什么是规则持久化 1.1.1、使用背景 1.1.2、规则管理的三种模式 a&#xff09;原始模式 b&#xff09;pull 模式 c&#xff09;push 模式 1.2、实现 push 模式 1.2.1、修改 order-service 服务&#xff0c;使其监听 Nacos 配置中心 1.2.2、修…

基于SpringBoot+Vue的企业信息反馈平台

1 简介 企业客户信息反馈的需求和管理上的不断提升&#xff0c;企业客户信息反馈管理的潜力将无限扩大&#xff0c;企业客户信息反馈平台在业界被广泛关注&#xff0c;本平台及对此进行总体分析&#xff0c;将企业客户信息反馈信息管理的发展提供参考。企业客户信息反馈平台对企…

【多任务案例:猫狗脸部定位与分类】

【猫狗脸部定位与识别】 1 引言2 损失函数3 The Oxford-IIIT Pet Dataset数据集4 数据预处理4 创建模型输入5 自定义数据集加载方式6 显示一批次数据7 创建定位模型8 模型训练9 绘制损失曲线10 模型保存与预测 1 引言 猫狗脸部定位与识别分为定位和识别&#xff0c;即定位猫狗…

批量导入、筛选与删除,文件改名从未如此简单!

您是否曾经为了给文件夹中的文件批量改名而感到烦恼&#xff1f;现在&#xff0c;有了我们的文件批量改名工具&#xff0c;这些问题都将成为过去&#xff01; 第一步&#xff0c;我们打开需要改名文件夹&#xff0c;可以看到里面文件名很多&#xff0c;很乱。 第二步进入文件批…

Acwing 844. 走迷宫

Acwing 844. 走迷宫 知识点题目描述思路讲解代码展示 知识点 BFS 题目描述 思路讲解 宽搜可以搜到最短路径&#xff1a; 代码展示 #include <cstring> #include <iostream> #include <algorithm> #include <queue>using namespace std;typedef pa…

传输层协议—UDP协议

传输层协议—UDP协议 文章目录 传输层协议—UDP协议传输层再谈端口号端口号范围划分pidofnetstat UDP协议端格式UDP报文UDP特点UDP缓冲区基于UDP的应用层协议 传输层 在学习HTTP/HTTPS等应用层协议时&#xff0c;为了方便理解&#xff0c;可以简单认为HTTP将请求和响应直接发送…

基于Java的图书个性化推荐系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…

基于Java的校园失物招领平台设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…

E. Mishap in Club

题目&#xff1a; 样例1&#xff1a; 输入 --输出 1 样例2&#xff1a; 输入 --- 输出 3 思路&#xff1a; 数学贪心模拟思路&#xff0c;由于不知道在俱乐部的人数和在外面的人数&#xff0c;又要尽可能少的人数&#xff0c;那么定义两个变量&#xff0c;一个是里面的人数 i…