JAVA:多线程常见的面试题和答案

news2024/12/23 10:25:59

请关注微信公众号:拾荒的小海螺
博客地址:http://lsk-ww.cn/

1、并发编程三要素?

  • 原 子 性
    原子性指的是一个或者多个操作,要么全部执行并且在执行的过程中不被其他操作打断,要么就全部都不执行。
  • 可 见 性
    可见性指多个线程操作一个共享变量时,其中一个线程对变量进行修改后,其他线程可以立即看到修改的结果。
  • 有 序 性
    有序性,即程序的执行顺序按照代码的先后顺序来执行。

1、Java中的volatile关键字有什么作用?

答:volatile关键字在Java中主要用于变量的同步,其核心作用可以概括为两点:

  • 保证内存可见性: 当一个变量定义为volatile之后,它会保证对所有线程的可见性。这意味着当一个线程修改了一个volatile变量的值,新值对于其他线程来说是立即可见的。
  • 禁止指令重排序: volatile还可以防止指令重排序优化。在没有volatile修饰的多线程程序中,为了提高性能,编译器和处理器可能会对指令进行重排序,但是一旦变量被volatile修饰,就会禁止这种重排序,以确保程序的执行顺序与代码的顺序相同。

虽然volatile可以保证单次读/写的原子性,但它无法保证整个操作的原子性。例如,volatile变量的i++操作无法保证原子性。

2、创建线程的方式有哪些?

  • 通过继承 Thread 类创建线程类
  • 实现 Runnable 接口创建线程类
  • 通过 Callable 和 Future 接口创建线

3、Java 如何保证线程安全?

  • 使用同步代码块
  • 使用同步方法
  • 使用 Lock 锁机制, 通过创建 Lock 对象,采用 lock()加锁,unlock()解锁,来保护指
    定的代码块。

4、描述 Synchronized、ReentrantLock 的区别 ?

  • synchronized 是关键字,ReentrantLock 是 API 接口
  • Lock 需要手动加锁,手动释放锁
  • synchronized 不可中断,ReentrantLock 可中断、可超时
  • synchronized 是非公平锁,ReentrantLock 公平、非公平皆可
  • ReentrantLock 支持 Condition,多条

5、在Java中wait和sleep方法的不同?

答:通常会在电话面试中经常被问到的Java线程面试问题。最大的不同是在等待时wait会释放锁,而sleep一直持有锁。Wait通常被用于线程间交互,sleep通常被用于暂停执行。

6、为什么我们调用 start()方法时会执行 run()方法,为什么我们不能直接调用 run()方法?

答:当你调用 start()方法时你将创建新的线程,并且执行在 run()方法里的代码 。但是如果你直接调用 run()方法,它不会创建新的线程也不会执行调用线程的代码 ,只会把 run 方法当作普通方法去执行。

7、Java 中用到的线程调度算法是什么?

答:计算机通常只有一个 CPU,在任意时刻只 能执行一条机器指令,每个线程只有获得CPU 的使用权才能 执行指令 .所谓多线程的并发运行,其实是指从宏观上看,各个线程轮流获得 CPU 的使用权,分别执行 各自的任务.在运行池中,会有多个处于就绪状态的线程在等待 CPU,JAVA 虚拟机的 一项任务就是负责线程 的调度 ,线程调度是指按照特定机制为多个线程分配 CPU 的使用权.。

有两种调度模型:分时调度模型和抢占式调度模型。

分时调度模型是指让所有的线程轮流获得 cpu 的使 用权,并且平均分配每个线程占用的 CPU 的时间片这个也比较好理解。

java 虚拟机采用抢占式调度模型,是指优先让可运行池中优先级高的线程占用CPU,如果可运行池中 的线程优 先级相同,那么就随机 选择一个线程,使其占用CPU。处于运行状态的 线程会一 直运行,直至它不得不 放弃 CPU。

8、什么是 Daemon 线程?它有什么意义?

答:所谓后台(daemon)线程,是指在程序运行的时候在后台提供一种通用服务的线程,并且这个线程并不属于程序中不可或缺的部分。因此,当所有的非后台线程结束时,程序也就终止了,同时会杀死进程中的所有后台线程。反过来说,只要有任何非后台线程还在运行,程序就不会终止。必须在线程启动之前调用setDaemon()方法,才能把它设置为后台线程。

注意:后台进程在不执行 finally子句的情况下就会终止其 run()方法。

比如:JVM 的垃圾回收线程就是 Daemon 线程 ,Finalizer 也是守护线程。

9、CyclicBarrier 和 CountDownLatch 的区别

  • CountDownLatch 简单的说就是一个线程等待,直到他所等待的其他线程都执行完成并且调用 countDown()方法发出通知后,当前线程才可以继续执行。

  • cyclicBarrier 是所有线程都进行等待,直到所有线程都准备好进入 await()方法之后,所有线程同时开始执行!

  • CountDownLatch 的计数器只能 使用一次。而 CyclicBarrier 的计数器可以使用 reset() 方法重置。所以 CyclicBarrier 能处理更为复杂的业务场景,比如如果计算发生错误,可以重置计数器,并让线程们重新执行一次。

  • CyclicBarrier 还提供其他有用的方法,比如 getNumberWaiting 方法可以获得 CyclicBarrier 阻塞的线程数量。isBroken 方法用来知道阻塞的线程是否被中断 。如果被中断返回 true,否则返回 false。

10、什么是 CAS 与其 常见的问题?

答:CAS是一种基于锁的操作,而且是乐观锁。在 java 中锁分为乐观锁和悲观锁。悲观锁是将资源锁住,等一个之前获得锁的线程释放锁之后,下一个线程才可以访问。而乐观锁采取了一种宽泛的态度,通过某种方式不加锁来处理资源,比如通过给记录加 version 来获取数据,性能较悲观锁有很大的提高。

CAS常见的问题:

  • CAS 容 易 造 成 ABA 问 题
    一个线程 a 将数值改成了 b,接着又改成了 a,此时 CAS 认为是没有变化,其实是已经变化过了,而这个问题的解决方案可以使用版本号标识,每操作一次version 加 1。在 java5 中,已经提供了 AtomicStampedReference 来解决问题。
  • 不 能 保 证 代 码 块 的 原 子 性
    CAS 机制所保证的知识一个变量的原子性操作 ,而不能保证整个代码块的原子性。比如需要保证 3 个变量共同进行原子性的更新,就不得不使用 synchronized 了。
  • CAS 造 成 CPU 利 用 率增 加
    之前说过了 CAS 里面是一个循环判断的过程,如果线程一直没有获取到状态,cpu资源会一直被占用

11、线程池的优点?

  • 重用存在的线程,减少对象创建销毁的开销。
  • 可有效的控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。
  • 提供定时执行、定期执行、单线程、并发数控制 等功能。

12、常用的并发工具类有哪些?

  • CountDownLatch
  • CyclicBarrier
  • Semaphore
  • Exchanger

13、Java 线程具有五中基本状态

  • 新 建 状 态(New):当线程对象对创建后,即进入了新建状态,如:Thread t = new MyThread();
  • 就 绪 状 态 ( Runnable) :当 调用线程对象的 start()方法(t.start();),线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好了准备,随时等待 CPU 调度执行,并不是说执行了 t.start()此线程立即就会执行;
  • 运 行 状 态 ( Running):当 CPU 开始调度处于就绪状态的线程时,此时线程才得以真 正执行,即进入到 运行状态 。注:就 绪状 态是进入到运 行状态的 唯一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中;
  • 阻 塞 状 态(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对 CPU的使用权 ,停止执行 ,此时进入阻塞 状态,直到其进 入到就绪状态 ,才 有机 会再次被 CPU 调用以进入到运行状态。
  • 死 亡 状 态(Dead):线程执行完了或者因异常退出了 run()方法,该线程结束生命周期
    在这里插入图片描述

14、线程池的创建方式有哪些

  • newSingleThreadExecutor() 创建一个单线程化的线程池;
  • newFixedThreadPool() 创建固定线程数量的线程池;
  • newCachedThreadPool() 创建一个可缓存的线程池,若线程数超过处理所需,缓存一段时间后会回收,若线程数不够,则新建线程。
  • newScheduledThreadPool() 创建一个可以延迟或定期执行任务的线程池;
  • newSingleThreadScheduledExecutor()创建一个单线程执行器,该执行器可以安排命令在给定延迟后运行,或定期执行;
  • newWorkStealingPool() 使用可用处理器数量作为其目标并行度级别创建工作窃取线程池 [ JDK1.8新增]。
  • 创建ThreadPoolExecutor对象来实现自定义线程池创建

FixedThreadPool 和 SingleThreadExecutor 传入的最后一个参数阻塞队列 ”workQueue“,默认的长度INTEGER.MAX_VALUE,而它们允许的最大线程数量又是有限的,所以当请求线程的任务过多线程不够用时,它们会在队列中等待,又因为队列的长度特别长,所以可能会堆积大量的请求,导致OOM。

CachedThreadPool 和 ScheduledThreadPool 它们的阻塞队列长度有限,但是传入的第二个参数maximumPoolSize 为Integer.MAX_VALUE,这就意味着当请求线程的任务过多线程不够而且队列也满了的时候,线程池就会创建新的线程,因为它允许的最大线程数量是相当大的,所以可能会创建大量线程,导致OOM。

15、synchronized 的作用?

答:在 Java 中,synchronized 关键字是用来控制线程同步的,就是在多线程的环境下,控制 synchronized 代码段不被多个线程同时执行。synchronized 既可以加在一段代码上,也可以加在方法上。

16、什么是 AQS

答:AQS 是 AbustactQueuedSynchronizer 的简称, 它是一个 Java 提高的底层同步工具类,用一个 int 类型的变量表示同步状态,并提供了一系列的 CAS 操作来管理这个同步状态。
AQS 是一个用来构建锁和同步器的框架,使用 AQS 能简单且高效地构造出应用广泛的大量的同步器,比如我们提到的ReentrantLock,Semaphore,其他的诸如ReentrantReadWriteLock,SynchronousQueue,FutureTask 等等皆是基于AQS 的。

AQS 支持两种同步方式:

  • 独占式
  • 共享式

17、sleep 方法和 wait 方法有什么区别?

答:这个问题常问,sleep 方法和 wait 方法都可以用来放弃 CPU 一定的时间,不同点在于如果线程持有某个对象的监视器,sleep 方法 不会放弃这个对象的监 视器,wait 方法会放弃这个对象的监视器。

18、ThreadLocal 是什么?有什么用?

答:ThreadLocal 是一个本地线程副本变量工 具类。主要用于将私有线程和该 线程存放的副本对象做一个映射,各个线程之间的变量互不干扰,在高并发场景下,可以实现无状态的调用,特别适用于各个线程依赖不通的变量值完成操作的场景。简单说 ThreadLocal 就是一种以空间换 时间的做法,在每个 Thread 里面维护了一个以开地址法实现的 ThreadLocal.ThreadLocalMap,把数据进行隔离,数据不共享,自然就没有线程安全方面的问题了。

19、ConcurrentHashMap 的并发度是什么

答:ConcurrentHashMap 的并 发度 就是 segment 的大 小, 默认 为 16,这 意味 着最多同 时可 以有 16 条线 程操 作 ConcurrentHashMap,这 也是ConcurrentHashMap 对 Hashtable 的最 大优 势, 任何 情 况下 ,Hashtable 能同时有 两条 线程 获取 Hashtable 中的 数据 吗?

20、什么是多线程的上下文切换

答:多线程的上下文切换是指 CPU 控制权由 一个已经正在运行的线程切换到另外一个就绪并等待获取 CPU 执行权的线程的过程。

21、什么是线程调度器(Thread Scheduler)和时间分片(TimeSlicing)?

答:线程调度器是一个操作系统服务,它负责为 Runnable 状态的线程分配 CPU 时间。一旦我们创建一个线程并启动它,它的执行便依赖于线程调度器的实现。

时间分片是指将可用的 CPU 时间分配给可用的 Runnable 线程的过程。分配 CPU 时间可以基于线程优先级或者线程等待的时间。线程 调度并不受到 Java 虚拟机控制,所以由应用程序来控制它是更好的选择(也就是说不要让你的程序依赖于线程的优
先级)。

22、Java 线程数过多会造成什么异常?

  • 线 程 的 生 命 周 期 开 销 非 常 高
  • 消 耗 过 多 的 CPU 资源
    如果可运行的线程数量多于可用处理器的数量,那么有线程将会被闲置。大量空闲的线程会占用许多内存,给垃圾回收器带来压力,而且大量的线程在竞争 CPU资源时还将产生其他性能的开销。
  • 降 低 稳 定 性
    JVM 在可创建线程的数 量上存在一个限制 ,这个限制值将随着平台的不同而不同,并且承受着多个因素制约,包括 JVM 的启动参数、Thread 构造函数中请求栈的大小,以及底层操作系统对线程的限制等。如果破坏了这些限制,那么可能抛出OutOfMemoryError 异常。

23、线程池中核心线程数量大小怎么设置?

  • CPU密集型任务:
    比如像加解密,压缩、计算等一系列需要大量耗费 CPU 资源的任务,大部分场景下都是纯 CPU 计算。尽量使用较小的线程池,一般为CPU核心数+1。因为CPU密集型任务使得CPU使用率很高,若开过多的线程数,会造成CPU过度切换。
  • IO密集型任务:
    比如像 MySQL 数据库、文件的读写、网络通信等任务,这类任务不会特别消耗 CPU 资源,但是 IO 操作比较耗时,会占用比较多时间。可以使用稍大的线程池,一般为2*CPU核心数。IO密集型任务CPU使用率并不高,因此可以让CPU在等待IO的时候有其他线程去处理别的任务,充分利用CPU时间。

另外:线程的平均工作时间所占比例越高,就需要越少的线程;线程的平均等待时间所占比例越高,就需要越多的线程;
以上只是理论值,实际项目中建议在本地或者测试环境进行多次调优,找到相对理想的值大小。

24、说说submit(和 execute两个方法有什么区别?

答:submit() 和 execute() 都是用来执行线程池的,只不过使用 execute() 执行线程池不能有返回方法,而使用 submit() 可以使用 Future 接收线程池执行的返回值。

25、volatile如何保证可见性?

答:Volatile是通过MESI缓存一致性协议和总线嗅探机制来保证可见性的

  • 什么是MESI协议?
    MESI协议其实是一个变量在内存中的不同状态!MESI 是指4种状态的首字
M 修改 (Modified) 当一个线程要修改便令
E 独享、互斥 (Exclusive) 当一个线程拿到了共享变量,此时为独享状态!
S 共享 (Shared) 当多个线程都拿到了共享变量,此时为共享状态!
I 无效 (Invalid) 线程丢弃了自己工作内存中的变量,为无效状态!
  • MESI协议如何保证可见性?
    首先cpu会根据共享变量是否带有Volatile字段,来决定是否使用MESI协议保证缓存一致性。如果有Volatile,汇编层面会对变量加上Lock前缀,当一个线程修改变量的值后,会马上经过store、write等原子操作修改主内存的值(如果不加Lock前缀不会马上同步),为什么监听到修改会马上同步呢?就是为了触发cpu的嗅探机制,及时失效其他线程变量副本。
  • cpu总线嗅探机制
    cpu总线嗅探机制监听到这个变量被修改,就会把其他线程的变量副本由共享S置为无效I,当其他线程在使用变量副本时,发现其已经无效,就回去主内存中拿一个最新的值。
  • 在写入主内存时为什么要加锁?在哪里加锁?
    变量被修改后同步到主内存的过程中会在store之前加锁,写完后解锁,这个锁只有在修改的时候才会加,锁粒度非常小。因为在store时可能已经经过了总线,但此时还没有write进主内存,总线却触发了嗅探机制,其他线程的变量已失效,当其他线程去主内存读最新数据时,新数据还未write进来,产生脏数据!
  • Lock前缀的作用
    使CPU缓存数据立即写会主内存(Volatile修饰的变量会带lock前缀)触发总线嗅探机制和缓存一致性协议MESI来失效其他线程的变量
    在这里插入图片描述

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

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

相关文章

linux镜像虚拟机创建共享文件夹详细步骤 -- 和本地电脑传输文件

主机与虚拟机之间传递文件,最快捷的方法莫过于共享文件夹。此方法不需要复制文件,而且可以节省硬盘空间。 具体设置步骤如下: 打开自己的电脑,创建共享的文件夹,完成后鼠标右击刚刚创建的共享文件夹,选择…

深入理解Python中的包与模块

新书上架~👇全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我👆,收藏下次不迷路┗|`O′|┛ 嗷~~ 目录 一、包的概述与功能 代码案例:包的结构 二、模块的划分与组合 划分模块的方法…

去除字符串中的空格和特殊字符

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 用户在输入数据时,可能会无意中输入多余的空格,或在一些情况下,字符串前后不允许出现空格和特殊字符,…

前端应用开发实验:表单控件绑定

目录 实验目的相关知识点实验内容代码实现效果 实验目的 (1)熟练掌握应用v-model指令实现双向数据绑定的方法,学会使用 v-model指令绑定文本框、复选框、单选按钮、下拉菜单; (2)学会值绑定(将…

【Unity2D 2022:Particle System】添加粒子特效

一、创建粒子系统游戏物体 1. 创建粒子系统游戏物体Smog Effect 2. 给粒子特效添加精灵贴图 (1)启用Texture Sheet Animation(纹理表动画) (2)点击加号添加一个纹理,并将两张厌恶图片导入到纹理…

【文献阅读】极端事件、经济不确定性、原油期货价格泡沫投机

Extreme events, economic uncertainty and speculation on occurrences of price bubbles in crude oil futures 极端事件、经济不确定性、原油期货价格泡沫投机 本文考察了极端事件、经济不确定性和投机行为对原油期货价格泡沫的影响。为了更好地预测和估计原油期货的正/负价…

MySQL之创建高性能的索引(六)

创建高性能的索引 选择合适的索引列顺序 当使用前缀索引的时候,在某些条件值的基数比正常值高的时候,问题就来了。例如,在某些应用程序中,对于没有登录的用户,都将其用户名记录为"guest",在记录…

ChatGPT的基本原理是什么?又该如何提高其准确性?

在深入探索如何提升ChatGPT的准确性之前,让我们先来了解一下它的工作原理吧。ChatGPT是一种基于深度学习的自然语言生成模型,它通过预训练和微调两个关键步骤来学习和理解自然语言。 在预训练阶段,ChatGPT会接触到大规模的文本数据集&#x…

【Python】解决Python报错:TypeError: ‘xxx‘ object does not support item assignment

🧑 博主简介:阿里巴巴嵌入式技术专家,深耕嵌入式人工智能领域,具备多年的嵌入式硬件产品研发管理经验。 📒 博客介绍:分享嵌入式开发领域的相关知识、经验、思考和感悟,欢迎关注。提供嵌入式方向…

opencascade 笔记

opencascade 画一个无限大的面 在 OpenCascade 中&#xff0c;要绘制一个无限大的面&#xff0c;你可以使用 gp_Pln 类来定义一个平面&#xff0c;然后将其绘制出来。这里是一个示例代码&#xff0c;演示如何在 OpenCascade 中绘制一个无限大的平面&#xff1a; #include <…

设计模式详解(六):适配器模式——Adapter

目录导航 适配器模式及其作用现实生活举例 适配器模式的好处适配器模式的实现关系图实现步骤 适配器模式的适用场景适配器模式示例 适配器模式及其作用 适配器模式是一种结构型设计模式。所谓结构型是指在代码结构方面的设计模式。适配器模式作为中间层&#xff0c;可以让交互…

论文笔记 Explicit Visual Prompting for Low-Level Structure Segmentations

通俗地解释视觉中的prompt 在视觉中的“prompt”&#xff08;提示&#xff09;可以用一种比较通俗的方式来理解&#xff1a; 什么是视觉中的提示&#xff1f; 想象一下&#xff0c;你有一个已经接受过大量训练的超级助手&#xff08;类似于预训练的模型&#xff09;&#xf…

SpringBoot注解--09--idea创建spring boot项目,java版本只能选择17和21

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 idea创建spring boot项目1.问题描述2.原因3.解决方法方案一&#xff1a;升级JDK版本至17或更高方案二&#xff1a;替换Spring初始化的源https://start.aliyun.com i…

【YOLOv10】2024年5月最新的YOLO系列模型Yolov10(论文阅读笔记) + 完整创新点说明 + 总结

&#x1f680;&#x1f680;&#x1f680; YOLOv10: 实时端到端的目标检测。YOLOv10比最先进的YOLOv9延迟时间更低&#xff0c;测试结果可以与YOLOv9媲美&#xff0c;可能会成为YOLO系列模型部署的“新选择”。 官方论文地址&#xff1a;https://arxiv.org/pdf/2405.14458 官方…

2024了,还有人在问为甚死锁?

大家好&#xff0c;我是javapub。 接上篇提到了锁&#xff0c;《InnoDB有哪些锁类型》。这么多的锁&#xff0c;你有遇到过死锁吗&#xff1f; 死锁是在事务数据库中会发生的一种特殊现象&#xff0c;多个事务在执行过程中&#xff0c;相互等待对方持有的资源&#xff0c;导致…

【Python编程实践2/3】Python图像处理模块(上)

目录 引言 目标 安装模块 Windows系统 macOS系统 路径 Windows路径 ​编辑macOS路径 windows路径报错 windows路径前的r 示例代码 windows快速查看路径 macOS快速查看路径 打开图片 展示图片 下节预告 总结 引言 欢迎各位大佬垂阅本篇Python实践博客&a…

Java Class类简介

一、类图&#xff1a; 二、基本介绍&#xff1a; 1. Class也是类&#xff0c;因此也继承了Object类。 2. Class类的对象不是new出来的&#xff0c;是系统创建的。 类加载器ClassLoader有个方法LoadClass()&#xff0c;将某个类对应的Class对象生成在堆中。 通过调试可以发现&am…

电脑显示由于找不到msvcr110.dll 无法继续执行如何处理?最简单的修复msvcr110.dll文件方法

电脑显示由于找不到msvcr110.dll 无法继续执行&#xff1f;当你看到这种提示的时候&#xff0c;请不要紧张&#xff0c;这种是属于dll文件丢失&#xff0c;解决起来还是比较简单的&#xff0c;下面会详细的列明多种找不到msvcr110.dll的解决方法。 一.找不到msvcr110.dll是怎么…

cesium绘制编辑区域

npm 安装也是可以的 #默认安装最新的 yarn add cesium#卸载插件 yarn remove cesium#安装指定版本的 yarn add cesium1.96.0#安装指定版本到测试环境 yarn add cesium1.96.0 -D yarn install turf/turf <template><div id"cesiumContainer"></div…

【Windows配置nginx开机自启】

Windows配置nginx开机自启 方式一&#xff1a;将nginx加入到windows服务中方式二&#xff1a;通过windows任务计划设定nginx开机自启 方式一&#xff1a;将nginx加入到windows服务中 下载window service wraper&#xff08;https://github.com/winsw/winsw/releases&#xff0…