【java八股文】之多线程篇

1、简述线程、进程的基本概念。以及他们之间关系是什么

进程:是程序的一次执行的过程,是系统运行的基本单位,其中包含着程序运行过程中一些内存空间和系统资源。进程在运行过程中都是相互独立,但是线程之间运行可以相互影响。


线程:是进程的更小的单位。一个进程中包含着多个线程。和进程不同的是线程是共享着进程中的内存空间和系统资源的。所以在切换线程过程中开销要比进程小的多。


2、线程池


2.1 线程池的七个参数

  • corePoolSize: 线程池核心线程数最大值
  • maximumPoolSize: 线程池最大线程数大小
  • keepAliveTime: 线程池中非核心线程空闲的存活时间大小
  • unit: 线程空闲存活时间单位
  • workQueue: 存放任务的阻塞队列
  • threadFactory: 用于设置创建线程的工厂,可以给创建的线程设置有意义的名字,可方便排查问题。
  • handler: 线程池的饱和策略事件,主要有四种类型。

2.2 线程池的执行过程

当提交一个线程执行任务时候 ,先看有没有空闲的核心线程,如果有就执行,如果没有就看阻塞队列中有没有满的状态,如果没有放满则放入队列中,否则就直接看线程数量是否大于非核心线程数量,如果没有就直接创建一个非核心线程,否则就是按照指定的拒绝策略给处理。如果一个非核心线程在某个一段时间类是空闲的那么线程池就会把这个线程自动销毁掉。

2.3 四种拒绝策略

  • AbortPolicy(抛出一个异常,默认的)
  • DiscardPolicy(直接丢弃任务)
  • DiscardOldestPolicy(丢弃队列里最老的任务,将当前这个任务继续提交给线程池)
  • CallerRunsPolicy(交给线程池调用所在的线程进行处理)


2.4 五种阻塞队列

  • ArrayBlockingQueue(有界队列)是一个用数组实现的有界阻塞队列,按FIFO排序量。
  • LinkedBlockingQueue(可设置容量队列)基于链表结构的阻塞队列,按FIFO排序任务,容量可以选择进行设置,不设置的话,将是一个无边界的阻塞队列,最大长度为Integer.MAX_VALUE,吞吐量通常要高于ArrayBlockingQuene;newFixedThreadPool线程池使用了这个队列
  • DelayQueue(延迟队列)是一个任务定时周期的延迟执行的队列。根据指定的执行时间从小到大排序,否则根据插入到队列的先后排序。newScheduledThreadPool线程池使用了这个队列。
  • PriorityBlockingQueue(优先级队列)是具有优先级的无界阻塞队列;
  • SynchronousQueue(同步队列)一个不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQuene,newCachedThreadPool线程池使用了这个队列。


2.4 五种创建线程的方式池的方式

  • newFixedThreadPool (固定数目线程的线程池)
  • newCachedThreadPool(可缓存线程的线程池)
  • newSingleThreadExecutor(单线程的线程池)
  • newScheduledThreadPool(定时及周期执行的线程池)
  • new ThreadPoolExecutor() 自定义的方式创建

2.5 使用无界队列的线程池会导致内存飙升吗?

会的,newFixedThreadPool使用了无界的阻塞队列LinkedBlockingQueue,如果线程获取一个任务后,任务的执行时间比较长(比如,上面demo设置了10秒),会导致队列的任务越积越多,导致机器内存使用不停飙升,最终导致OOM。

3、线程、进程、协程的区别

进程:进程是操作系统分配系统资源和内存空间的最小单位。进程是独立的一块空间,所以资源和内存空间的切换是特别消耗资源的。

线程:线程也叫做轻量级的进程,是操作系统调用执行的最小单位。线程的资源是依赖于他的父进程,所以他的资源是共享的,线程的切换需要转换到内核态开销相对于小一些。

协程:协程是一种轻量级的线程,协程是直接在用户态就可以控制,具有对内核态来说是不可见的,所以协程的上下文切换更加的节约资源消耗。

4、什么是上下文的切换

上下文的切换指的是CPU寄存器和程序计数器存储的数据进行切换,而内存数据的改变只有在内核态才能进行。所以上下文切换对系统来说是巨大的成本。

  • 先是暂停原有的进程,保存好进程中寄存器中的数据在某个地方
  • 内存中获取下一个进程上下文,存储到寄存器中


5、Java有几种创建线程的方式

  • new 一个Thread
  • 继承Runnable类
  • 使用Callable
  • 使用线程池


6、sleep和wait区别

sleep 属于 Thread类,wait属于Object类
wait会释放掉锁,sleep不会释放锁
wait必须在同步代码方法和同步代码块中,sleep没有这一个限制
wait()要调用notify()或notifyall()唤醒,sleep()自动唤醒

7、Java的内存模型

JMM屏蔽了各种硬件和操作系统的内存访问差异,实现让Java程序在各平台都能够达到一致的内存访问效果,它定义了Java如何将程序中的变量在主存中读取

具体定义:所有变量都在主存中,主存是线程的共享区域,每个线程都有自己独有的工作内存,线程想要操作变量必须从主存中copy一份到自己的工作区域,每个独立内存区域相互隔离。

所以这个时候读写存在延迟,且不是原子操作,所以就出现了一些列的线程安全操作。比如 原子性、可见性、有序性。

 

8、保证并发安全的三大特性?

  • 原子性:一次或多次操作在执行期间不被其他线程影响
  • 可见性:当一个线程在工作内存修改了变量,其他线程能立刻知道(利用内存原子操作解决或者内存屏障或者lock前缀)
  • 有序性:JVM对指令的优化会让指令执行顺序改变,有序性是禁止指令重排(内存屏障)

9、ThreadLocal原理

每一个线程创建变量的副本,不同线程间是不可见的,保证线程安全。每个线程都维护一个ThreadLocalMap,key为threadlocal实例,value是保存的副本。

但是使用ThreadLocal会存在内存泄漏问题,因为key 是弱引用,value是强引用,每次GC时key都会回收,而value不会被回收。所以为了解决内存泄漏问题,可以在每次使用完后删除value或者使用static修饰ThreadLocal,可以随时的获取value。

第二个会出现内存溢出问题,如果使用的是线程池的方式去使用ThreadLocal话,那么就会出现存储的value一直存在,这样就一直堆积。

10、什么是CAS锁

CAS锁可以保证原子性,思想是更新内存是会判断其内存的值是否被修改了,如果没有被修改就直接更新,如果被修改了,就得重新去获取值,知道更新为止。这样是有缺点的:

  • 只能支持一个变量的原子操作,不能保证整个代码块的原子操作
  • CAS频繁的失败会造成CPU的开销打
  • 会出现ABA问题

解决ABA问题,可以通过加入版本控制

11、Synchronized锁原理和优化


在JDK1.6以后Synchronized引入了偏向锁、轻量级锁、重量级锁、锁的粗化、锁消除的优化。并发性能基本和Lock持平的。

  • 偏向锁:是不存竞争情况下,从而在后续的代码块中没有加锁解锁的开销
  • 轻量级锁:轻量级锁所适应的场景是线程交替执行同步块的场合
  • 重量级锁:重量级锁首先会经过一定次数的CAS自旋操作获取锁,如果获取失败,存在同一时间多个线程访问同一把锁的场合,就会导致轻量级锁膨胀为重量级锁。是在竞争激烈的情况下创建一个monitor对象,并且将线程挂起,而挂起就要切换到内核状态执行。从而开销非常大。

轻量级锁:当锁是偏向锁时,有另外一个线程来访问,会撤销掉偏向锁,然后升级为轻量级锁,这个线程会通过自旋方式不断获取锁,不会阻塞,提高性能

重量级锁:轻量级锁尝试去获取到锁,如果获取失败线程就会进入阻塞状态,该锁会升级为重量级锁,重量级锁时,来竞争锁的所有线程都会阻塞,性能降低

注意,锁只能升级不能降级


12、synchronized和ReentrantLock的区别


实现方面:一个是JVM层次通过,(监视器锁)monitor实现的。一个是通过AQS实现的
相应中断不同:ReentrantLock 可以响应中断,解决死锁的问题,而 synchronized 不能响应中断。
锁的类型不同:synchronized 是非公平的锁,而ReentrantLock即可以是公平的也可以是非公平的
获取锁的方式不同:synchronized 是自动加锁和释放锁的,而 ReentrantLock 需要手动加锁和释放锁。

13、为什么AQS使用的双向链表

因为有一些线程可能发生中断 ,而发生中断时候就需要在同步阻塞队列中删除掉,这个时候就会用到prev和next方便删除掉中间的节点

14、有哪些常见的AQS类

  • ReentrantLock 独占锁
  • Semaphore 共享锁(限流有限资源)
  • CountDownLatch 共享锁(合并汇总)
  • CyclicBarrier 独占锁 + 条件队列
  • ReentrantReadWriteLock 读写锁


15、死锁产生的4个必要条件

  • 互斥条件:进程要求对所匹配的资源进行排他性控制,即是一段时间内某资源仅为一进程所占有
  • 请求和保持条件:当进程因请求资源而阻塞时,对已获得的资源保持不放
  • 不剥夺条件:进程已获得的资源在未使用完之前不,不能剥夺,只能在使用完时有自己释放
  • 环路等待条件:在发生死锁时,必须存在一个进程–资源得环星链

16、预防死锁

  • 资源一次性得分配:一次性分配所有得资源,这样就不会有请求了(破坏请求条件);只要一个资源得不到分配,也不给这个进程分配其他得资源(破坏请求保持条件)
  • 可剥夺条件:即当某个进程获得部分资源,得不到其他得资源,则释放已有得资源(破坏补课剥夺得条件)
  • 资源有序分配法:系统分配资源编号,每一个进程按编号递增的顺序请求资源,释放则反之(环路破坏)

17、解除死锁

  • 剥夺资源:从其它进程剥夺足够数量的资源给死锁进程,以解除死锁状态;
  • 撤消进程:可以直接撤消死锁进程或撤消代价最小的进程,直至有足够的资源可用,死锁状态.消除为止;所谓代价是指优先级、运行代价、进程的重要性和价值等。

18、CPU密集型和IO密集型 的线程数设置

  • CPU 密集型:对于这样的任务最佳的线程数为CPU核心数的1~2倍,如果设置过多的线程,就会造成不必要的CPU上下文切换,性能相对于比较低
  • IO密集任务:由于IO读写是比较消耗时间的,并不会特别的消耗CPU的资源。对于这种任务最大的线程数一般大于CPU核心数的很多倍。
  • 线程数 = CPU 核心数 *(1+平均等待时间/平均工作时间
     

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Nginx服务安装

Nginx(发音为[engine x])专为性能优化而开发,其最知名的优点是它的稳定性和低系统资源消 耗,以及对HTTP并发连接的高处理能力(单台物理服务器可支持30000~50000个并发请求)。正因 为如此,大量提供社交网络、…

视频号下载小助手:教你微信视频号怎么提取视频出来

作为一名剪辑师或自由职业者,我们作为短视频创作者有时候需要下载多个视频用于制作多个解说系列的视频或者连续剧。然而,下载这些视频通常需要花费大量时间和精力,尤其是在没有合适的工具的情况下,让我们制作视频也确实困难,那么我们该如何解决呢&#x…

科研绘图(三)百分比堆叠线条图

百分比堆叠线条图是一种数据可视化工具,它结合了堆叠面积图和线条图的特点。在这种图表中,时间序列数据被分成几个部分,每个部分代表一个类别,所有类别的值加起来总和为100%。这种图的每个点的堆叠区域代表不同类别在特定时间点的…

软件测试|selenium 元素无此属性NoSuchAttributeException问题分析与解决

简介 在使用Selenium进行Web自动化测试时,我们可能会遇到NoSuchAttributeException异常。这个异常通常在尝试访问一个元素的属性(attribute)时抛出,但该属性不存在。本文将介绍NoSuchAttributeException异常的常见原因以及解决方…

使用Web自动化测试工具显著好处

随着互联网技术的飞速发展,Web应用程序在企业中的重要性不断上升。为了确保Web应用程序的质量和稳定性,许多企业转向了Web自动化测试工具。下面是使用Web自动化测试工具的一些显著好处: 1. 提高测试覆盖率 Web自动化测试工具可以模拟用户与We…

[redis] redis高可用之持久化

一、Redis 高可用的相关知识 1.1 什么是高可用 在web服务器中,高可用是指服务器可以正常访问的时间,衡量的标准是在多长时间内可以提供正常服务(99.9%、99.99%、99.999%等等)。 但是在Redis语境中,高可用的含义似乎要宽泛一些,…

软件测试公式之如何高质量的做BUG分析?

对于BUG分析,测试人员再熟悉不过了。但如果是面对大量的BUG,要如何有效的分析呢?有什么好的方案和行动项?今天聊聊这个话题。 01 BUG分析简单可以分为两类:宏观BUG分析 和 微观BUG分析。 宏观BUG分析:在…

Rust-变量

Rust的变量必须先声明后使用。对于局部变量,最常见的声明语法为: let variable:i32 100;与传统的C/C语言相比,Rust的变量声明语法不同。这样设计主要有以下几个方面的考虑。 语法分析更容易 从语法分析的角度来说,Rust的变量声明…

[element-ui] 级联选择器el-cascader不触发change事件

el-cascader 使用官网的数据是可以的 官网数据中最后一级没有children // 删除最后一级的children changeKey(arr) {for (var i0; i<arr.length; i) {if (arr[i].children.length) {this.changeKey(arr[i].children)} else {delete arr[i].children}} ]就可以了 参考&…

JavaScript高级程序设计读书记录(十二):函数

函数是ECMAScript中最有意思的部分之一&#xff0c;这主要是因为函数实际上是对象。每个函数都是Function 类型的实例&#xff0c;而 Function 也有属性和方法&#xff0c;跟其他引用类型一样。因为函数是对象&#xff0c;所以函数名就是 指向函数对象的指针&#xff0c;而且不…

蓝凌EIS智慧协同平台 frm_form_upload.aspx 文件上传漏洞复现

0x01 产品简介 蓝凌EIS智慧协同平台是一款专为企业提供高效协同办公和团队合作的产品。该平台集成了各种协同工具和功能,旨在提升企业内部沟通、协作和信息共享的效率。 0x02 漏洞概述 蓝凌EIS智慧协同平台 frm_form_upload.aspx接口处存在任意文件上传漏洞,未经过身份认证…

李沐之使用块的网络VGG

目录 1.VGG 2.代码实现 1.VGG n层是指可以有N个窗口3*3&#xff0c;填充为1的卷积层。有m个通道&#xff0c;这里输入和输出都是一样的。 VGG就是替换掉AlexNet整个卷积层的架构。 直径大小表示占内存&#xff0c;横坐标表示速度&#xff0c;纵坐标表示精确度。 2.代码实现 …