盘点最近线程池的几个面试重要考点

news2024/11/8 12:39:25

有点惊叹最近的面试题,因为从之前的基础的面试题,到之后的一些涉及到分布式和微服务的面试题,再到现在的线程池的一些面试题,反正不同的面试官,就有不同的针对方向,可能现在的面试官比较想考验你的多方面的能力吧,而最近,一个读者就反馈说,面试官全程就从线程这块入手,整的自己有点尴尬,但是好在有惊无险的入职了,我们来看看面试官都问了什么内容?

进程和线程的概念,你能说一下自己的理解么?这个问题,有点基础,不过肯定是之后的开胃小菜。

进程和线程的关系

进程就是应用程序在内存中分配的空间,也就是正在运行的程序,各个进程之间互不干扰。同时进程保存着程序每一个时刻运行的状态。

让一个线程执行一个子任务,这样一个进程就包含了多个线程,每个线程负责一个单独的子任务。

进程是一个独立的运行环境,而线程是在进程中执行的一个任务。他们两个本质的区别是是否单独占有内存地址空间及其它系统资源(比如I/O)

总得来说就是,线程是属于进程中的一个任务,应该算是包含的关系。

进程是操作系统进行资源分配的基本单位,而线程是操作系统进行调度的基本单位。

多进程的方式也可以实现并发,为什么我们要使用多线程?这个问题就有意思了,你如果不是很了解的话,这个问题还真不好回答。

多进程方式确实可以实现并发,但使用多线程,是比多进程有好处的。

1.进程间的通信比较复杂,而线程间的通信比较简单,通常情况下,我们需要使用共享资源,这些资源在线程间的通信比较容易。

2.进程是重量级的,而线程是轻量级的,故多线程方式的系统开销更小。

资源浪费属于一方面的有点,通信简单也是另外一方面的优点,就凭借这两点的内容,还能选择多进程?

线程池的内容

你在工作中使用过线程池么?为什么使用线程池?这个问题有点尴尬,为什么这么说?

如果你说你没用过,那你这在面试官这里就相当于只写 CRUD 的逻辑业务了,也不整点其他的内容。

如果你说你用过,你就得回答接下来的一系列关于线程池的问题了。这个阿粉还是推荐,实话实话,就算你没用过,那么也别瞎扯,不然你这给自己挖的坑,肯定自己得跳下去。

那么我们就从为什么使用线程池来入手分析呗。

首先我们就要思考一件事,不使用线程池的话,创建线程有什么弊端么?

在java中,如果每个请求到达就创建一个新线程,那对服务器的资源消耗是不是有点大,创建线程,销毁线程,创建线程,销毁线程,然后再各种线程之间来回的切换,这一来一回,是不是感觉资源浪费就体现出来了。

那么线程池会避免这个情况么?

这就出来了优点1了

创建/销毁线程需要消耗系统资源,线程池可以复用已创建的线程。

虽然这个优点很明确,但是还不是主要原因,主要原因如下:

控制并发的数量。并发数量过多,可能会导致资源消耗过多,从而造成服务器崩溃。(主要原因)

可以对线程做统一管理

分析一下线程池的原理 Java中的线程池顶层接口是Executor接口,但是使用的肯定不是这个,是 ThreadPoolExecutor

我们看看 ThreadPoolExecutor 构造函数

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }

竟然参数这么多,分别都代表什么意思呢?

int corePoolSize:该线程池中核心线程数最大值。

int maximumPoolSize:该线程池中线程总数最大值。

long keepAliveTime:非核心线程闲置超时时长。

TimeUnit unit:keepAliveTime的单位。

BlockingQueue workQueue:阻塞队列,维护着等待执行的Runnable任务对象。

corePoolSize核心线程最大值:这个值怎么确定?

一般这个问题是相对来说比较棘手的,如果面试官问这个问题,那一般的同学肯定头大,我知道啥意思,但是这个怎么设置,我怎么定义呢?

其实有个计算公式:

最佳线程数目 = ((线程等待时间+线程CPU时间)/线程CPU时间 )* CPU数目

            = (线程等待时间与线程CPU时间之比 + 1)* CPU数目

线程等待时间所占比例越高,需要越多线程。线程CPU时间所占比例越高,需要越少线程

maximumPoolSize :线程池中线程总数最大值

这个值实际上就是 核心线程数 + 非核心线程数量

keepAliveTime: 这个值如果设定了,那么非核心线程如果处于闲置状态超过该值,就会被销毁。

BlockingQueue:阻塞队列

看样子感觉像 MQ 里面的东西,想到队列,我们就又能联想到生产者和消费者,这时候就出现了个问题,为什么要有阻塞队列呢?

是不是就出现了消费者模式,生产者一直生产资源,消费者一直消费资源,资源存储在一个缓冲池中。

我们在实现这个模式的时候,多个线程操作共享变量,于是就带来了线程安全性的问题,造成重复消费和死锁,这时候阻塞队列就出现了,当缓冲池空了,我们需要阻塞消费者,唤醒生产者;当缓冲池满了,我们需要阻塞生产者,唤醒消费者。

而BlockingQueue提供了线程安全的队列访问方式,并发包下很多高级同步类的实现都是基于BlockingQueue实现的。

也就是说,你就只负责生产和消费,安全问题,JDK 来给你保证。

说到这里,我们不在继续往下延伸了,等下次阿粉直接在吧 BlockingQueue 完全的分析一波,应为 BlockingQueue 绝对得需要一个长篇的内容才能解释清楚。

分析完里面的参数,这时候,就得来看看线程池是怎么处理线程任务的,不然那怎么和面试官battle。

线程池是如何处理内部的线程任务的

public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
       int c = ctl.get();
       // 1.当前线程数小于corePoolSize,则调用addWorker创建核心线程执行任务
            if (workerCountOf(c) < corePoolSize) {
                if (addWorker(command, true))
                    return;
                c = ctl.get();
            }
            // 2.如果不小于corePoolSize,则将任务添加到workQueue队列。
            if (isRunning(c) && workQueue.offer(command)) {
                int recheck = ctl.get();
                //如果isRunning返回false(状态检查),则remove这个任务,然后执行拒绝策略。
                if (! isRunning(recheck) && remove(command))
                    reject(command);
                    //线程池处于running状态,但是没有线程,则创建线程
                else if (workerCountOf(recheck) == 0)
                    addWorker(null, false);
            }
            //如果放入workQueue失败,则创建非核心线程执行任务,
            //如果这时创建非核心线程失败(当前线程总数不小于maximumPoolSize时),就会执行拒绝策略。
            else if (!addWorker(command, false))
                reject(command);
}
                                      

在 execute 方法中,ctl.get()是获取线程池状态。

流程如下:

1,首先线程池判断基本线程池是否已满,没满,创建一个工作线程来执行任务。满了,则进入下个流程。

2,其次线程池判断工作队列是否已满?没满,则将新提交的任务存储在工作队列里。满了,则进入下个流程。

3,最后线程池判断整个线程池是否已满,没满,则创建一个新的工作线程来执行任务,满了,则交给饱和策略来处理这个任务。

如果你能把这些在面试的时候说清楚,那么至少在线程池这个知识点上,你是没有任何问题了,这样就可以愉快并且开心的走下一个知识点了。

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

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

相关文章

Hive(2):Apache Hive 安装部署

1 元数据相关名词 1.1 Metadata Metadata即元数据。元数据包含用Hive创建的database、table、表的位置、类型、属性&#xff0c;字段顺序类型等元信息。元数据存储在关系型数据库中。如hive内置的Derby、或者第三方如MySQL等。 1.2 Metastore Metastore即元数据服务。Metast…

Python中tqdm进度条的详细介绍(安装程序与耗时的迭代)

平时在做一些测试时候&#xff0c;是没有进度条出现的&#xff0c;这跟大家pip安装程序不一样(有安装进度条)&#xff0c;比如做遍历的时候&#xff1a;for i in range(10):time.sleep(0.5)print(i)只是每过0.5秒就进行打印输出&#xff0c;在这个等待过程是没有任何提示的&…

SAP ADM100-2.1 SAP系统启停过程

一、SAP系统开启过程 在SAP系统使用过程中维护硬件和修改SAP系统配置文件后重启SAP系统是有必要的。开启SAP系统是每个SAP系统管理员应该熟悉的初始过程。 每个SAP系统包含一个数据库和至少一个实例,JAVA栈SAP系统还有一个CS中央服务实例,ABAP栈SAP系统含有一个ABAP CS中央服…

springboot2.5集成log4j2报错

报错信息&#xff1a; SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". SLF4J: Defaulting to no-operation (NOP) logger implementation SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details. 修改依赖 把依…

【01Studio MaixPy AI K210】22.ESP8266与服务器连接的问题及处理

目录 前提 问题 处理 前提 WiFi的账号密码输入正确 ESP8266的主题与服务器的主题一致 代码的服务器网址正确 ESP8266正确连接核心板的引脚 ESP8266返回“OK” simple.py文件以发送到开发板 WiFi已打开 问题 1.连接上WiFi&#xff0c;已输出IP信息&#xff0c;但是仍然…

48.Isaac教程--GMapping应用程序

GMapping应用程序 GMapping 是一个使用 OpenSlam 软件库的地图生成工具。 该应用程序允许您创建地图以在其他应用程序中使用。 GMapping 应用程序使用 Carter 参考机器人的 LIDAR 功能。 注意 建图是一项计算密集型和存储密集型活动&#xff0c;可能需要微调才能生成合适的…

Hive(1):Apache Hive入门

1 Apache Hive概述 1.1 什么是Hive Apache Hive是一款建立在Hadoop之上的开源数据仓库系统&#xff0c;可以将存储在Hadoop文件中的结构化、半结构化数据文件映射为一张数据库表&#xff0c;基于表提供了一种类似SQL的查询模型&#xff0c;称为Hive查询语言&#xff08;HQL&a…

记OPNsense防火墙的安装过程 - 安全

前些天在网上看到防火墙软件OPNsense&#xff0c;对其有了兴趣&#xff0c;以前写过一个其前面的一个软件M0n0wall( 关于m0n0wall的安装及配置 )&#xff0c;当时也是非常有名的防火墙&#xff0c;现在有了OPNsense&#xff0c;这个老防火墙已经停止更新了。 下面对OPNsense防火…

MFC如何实现屏幕截图

目录一 程序实现效果二 程序实现思路三 具体实现一 程序实现效果 本文描述了MFC中实现屏幕截图的一种方式&#xff0c;程序界面如下&#xff1a; 单击【开始截屏】&#xff0c;按住鼠标左键&#xff0c;一直拖动到需要截屏的矩形的右下角&#xff0c;松开鼠标左键&#xff0c…

工业设备数据采集调研要点

一、概述 当一家客户提出需要采集设备的数据&#xff0c;通常需要对设备、通讯、采集方案进行确认。此时我们需要做两件事&#xff1a; 1、向客户要设备清单&#xff0c;便于确认设备的数量。&#xff08;客户提供&#xff09; 2、确认设备信息、通讯接口信息、采集方案。&a…

图文详解 Java 泛型,写得太好了!

一、泛型的引入我们都知道&#xff0c;继承是面向对象的三大特性之一&#xff0c;比如在我们向集合中添加元素的过程中add()方法里填入的是Object类&#xff0c;而Object又是所有类的父类&#xff0c;这就产生了一个问题——添加的类型无法做到统一 由此就可能产生在遍历集合取…

OpenShift 4 - 在单节点 OpenShift 上部署 ODF 存储软件

《OpenShift / RHEL / DevSecOps 汇总目录》 说明&#xff1a;本文已经在支持 OpenShift 4.12 的 OpenShift Local 环境中验证 文章目录什么是 ODF LVM &#xff1f;为 OpenShift Local 增加额外存储设备安装并配置 ODF LVM Operator使用 ODF 创建 PVC/PV 验证什么是 ODF LVM &…

Mock的接口自动化测试如何测?

1.Mock实现原理和实现机制 在某些时候&#xff0c;后端在开发接口的时候&#xff0c;处理逻辑非常复杂&#xff0c;在测试的时候&#xff0c;后端在未完成接口的情况下该如何去测试呢&#xff1f; 我们需要测试&#xff0c;但是有些请求又需要修改一下参数&#xff0c;或者改…

寻找适合程序员的笔记软件

做为一个程序员,有两个东西是我们必需的.一个是搜索,另一个则是记录. 当我们遇到不会或解决不了的困难点时,我们会第一时间使用搜索(如Google)来寻找解决方案,而当我们积累与在技术上有任何心得时,我们会记录它. 因而,寻找一个合适的笔记软件,对程序员非常重要. 一) 程序员…

Apache Spark 机器学习 特征转换 1

分词器&#xff08;Tokenizer&#xff09; 分词是一个处理过程&#xff0c;其将文本句子分割成一系列独立的单词词汇集合&#xff0c;Spark提供Tokenizer分词器类&#xff0c;其提供的功能是使用分隔符的方式处理文本句子的特征转换&#xff0c;Spark提供RegexTokenizer分词器…

在PC上安装OpenSSL,生成证书

文章目录一.在编程 PC 上安装 OpenSSL1. 下载安装 OpenSSL2.生成CA认证3. 生成 Broker 证书4. 生成各个 Client 的证书一.在编程 PC 上安装 OpenSSL 为了使用带 TLS 安全证书的 ADS Over MQTT&#xff0c;在 MQTT 的 Server 和 Client 侧都需要证书以进行安全通信&#xff0c;…

安装vue-cli2和3以及创建vue2和vue3项目的步骤及区别

文章目录安装vue-cli2版本步骤1.下载vue-cli2问题1&#xff1a;安装Vue Cli出现EEXIST: file already exists, cmd shim ‘C:\Users\2.vue-cli2构建vue项目问题2&#xff1a;报错&#xff1a; vue-cli Failed to download repo vuejs-templates/webpack: connect ETIMEDOUT 19…

「兔了个兔」福兔贺春,纯CSS实现超精美月兔404界面(附源码)

&#x1f482;作者简介&#xff1a; THUNDER王&#xff0c;一名热爱财税和SAP ABAP编程以及热爱分享的博主。目前于江西师范大学会计学专业大二本科在读&#xff0c;同时任汉硕云&#xff08;广东&#xff09;科技有限公司ABAP开发顾问。在学习工作中&#xff0c;我通常使用偏后…

搭建一个FAQ智能问答系统/服务

FAQ智能问答系统 介绍 项目传送门&#xff1a;https://github.com/wzzzd/FAQ_system 构建了一个FAQ智能问答系统。 使用多种方法&#xff0c;实现FAQ的问题-模板匹配功能。 使用Tornado框架&#xff0c;部署成轻量级的Web服务应用。 整体框架如下。 流程 1.初始化流程 1.…

这福利给你要不要 — 用Python采集相亲网站女生数据

前言 俗话说学咱这行的男同志 找对象容易吗 这马上就要过完年了 是时候找找女朋友了 我在这里摸索到了个网站 或许你们可以来看看 送一波单身福利 不需要的也可以学学怎么采集这些数据呗 环境与模块 环境开发 Python 3.8Pycharm 模块使用 import parsel --> p…