Java全栈经典面试题剖析8】JavaSE高级 -- 线程同步、 线程通信、死锁、线程池
目录
面试题3.44 多线程的同步方式
面试题3.45 多线程安全问题怎么解决
面试题3.46 当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法?
面试题3.47 简述synchronized与java.util.concurrent.locks.Lock的异同?synchronized和Lock锁两者区别? 谈谈 synchronized和ReentrantLock的区别
面试题3.48 sleep()和wait()有什么区别?
面试题3.49 线程之间是如何通信的?
面试题3.50 为什么wait(),notify()和notifyAll()必须在同步方法或者同步块中被调用?
面试题3.51 线程阻塞有几种情况?遇到阻塞怎么解决?
面试题3.52 如何安全中断运行中的线程?interrupt()方法的作用?
面试题3.53 volatile关键字的作用,能保证线程安全吗
面试题3.54 Java 中 ++ 操作符是线程安全的吗?
面试题3.55 请说说ThreadLocal?请说说线程本地变量?请说说本地线程?
面试题3.56 死锁的原因
面试题3.57 死锁与活锁的区别,死锁与饥饿的区别?
面试题3.58 java多线程有几种实现方式?你推荐哪一种
面试题3.59 线程池的优点?
面试题3.60 什么是线程池?有哪几种创建方式?四种线程池的创建方式?
面试题3.61 HashMap如何实现线程安全? ConcurrentHashMap和Hashtable的区别?
面试题3.44 多线程的同步方式
【技术难度:2 出现频率:2 】
1.synchronized修饰的同步代码块;
2.synchronized修饰的同步方法;
3.Lock锁。
面试题3.45 多线程安全问题怎么解决
【技术难度: 2 出现频率:2 】
解决思路是尽量避免多个线程同时操作相同变量。
解决方案有这些:
1.多实例,为每个线程创建一个实例,缺点是浪费空间;
2.添加synchronized关键字,缺点是效率低,逐个线程排队执行;
3.使用本地线程变量ThreadLocal;
4.使用Lock锁,缺点是效率低,逐个线程排队执行;
5.使用局部变量,因为局部变量不存在线程安全的问题,缺点是多线程时不一定具备这种场景。
面试题3.46 当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法?
【技术难度:2 出现频率:1 】
假设这个线程进入的是该对象的synchronized实例方法,此时其它线程可以进入此对象的其它方法有未加锁的实例方法和类方法,以及synchronized加锁的类方法。
面试题3.47 简述synchronized与java.util.concurrent.locks.Lock的异同?synchronized和Lock锁两者区别? 谈谈 synchronized和ReentrantLock的区别
【技术难度: 2 出现频率:1 】
接下来以实现类ReentrantLock代表Lock锁来回答此问题:
第一层:
1.synchronized是java关键字; Lock是java接口,jdk1.5才出现;
2.synchronized会自动获取或释放锁,Lock锁需要调用lock()或unlock()方法手动获取或释放锁;
3.synchronized如果获取不到锁会一直等待,ReentrantLock如果获取不到锁可以设置时间,超过不等待;
第二层:
4.synchronized是非公平锁,ReentrantLock可以实现公平锁;
5.synchronized只能随机或者全部唤醒,ReentrantLock可以精确或分组唤醒;
6.synchronized锁适合少量代码的同步问题,Lock锁适合大量代码的同步问题。
拓展:
竞争激烈的情况下,Lock锁的性能优于synchronized。竞争不激烈的情况下,synchronized性能好一点,因为synchronized有个锁升级机制,根据竞争激烈程序给锁升级,从偏向锁到轻量级锁再到重量级锁,而到重量级锁的转换需要操作系统帮忙,需要花费较多时间。
面试题3.48 sleep()和wait()有什么区别?
【技术难度:1 出现频率: 1 】
1.sleep()是Thread类的静态方法,wait()是Object类的实例方法;
2.sleep不会释放对象锁,wait会释放对象锁;(会造成锁的二次释放吗?)
3.sleep的休眠时间到达后自动进入就绪状态,wait的线程必须由notify()或notifyAll()唤醒,唤醒后进入同步阻塞状态(重新竞争锁)。
面试题3.49 线程之间是如何通信的?
【技术难度: 2 出现频率:1 】
通过Object类的wait()、notify()、notifyAll(),以及Thread类的join()方法,可以进行消息传递,实现让线程等待或唤醒线程,
多线程之间通信是为了避免对同一共享资源的争夺。
面试题3.50 为什么wait(),notify()和notifyAll()必须在同步方法或者同步块中被调用?
【技术难度: 2 出现频率: 1 】
1.调用wait()的线程会释放锁,很显然,先获得锁才能释放锁;
2.notify()、notifyAll()是将锁交给调用了wait()方法的线程,让其继续执行下去,前提是自身获得了锁才能交出锁。
面试题3.51 线程阻塞有几种情况?遇到阻塞怎么解决?
【技术难度: 2 出现频率:2 】
线程阻塞的情况分三种:等待阻塞、同步阻塞、其他阻塞。
三种线程阻塞展开说是这样:
1.等待阻塞是指运行的线程执行了wait()方法,JVM会把该线程放入等待池中;
2.同步阻塞是指运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中;
3.其他阻塞是指运行的线程执行了sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
线程阻塞的解决方法有:
1.sleep()、wait()和join()方法引发的阻塞可以通过interrupt()方法中断;
2.同步锁引发的阻塞可以通过减少锁持有时间,读写锁分离,减小锁的粒度,锁分离,锁粗化等方式来优化锁的性能。
扩展(无需背诵):
阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。
面试题3.52 如何安全中断运行中的线程?interrupt()方法的作用?
【技术难度: 2 出现频率: 1 】
Java Thread 的API里面虽然提供了一个 stop() 方法,可以强行终止线程,但这种方式是不安全的,因为有可能线程的任务还没有完成,突然中断会导致出现运行结果不正确的问题。
因此,在 Thread 里面提供了一个 interrupt() 方法,这个方法要配合isInterrupted()方法来使用,就可以实现安全地中断线程运行。 这种实现方法并不是强制中断,而是告诉正在运行的线程,你可以停止了。何时实际中断,取决于正在运行的线程,所以,它能够保证线程运行结果的安全性。
public class SafeInterruptExample { public static void main(String[] args) { Thread worker = new Thread(new RunnableTask()); worker.start(); // 中断工作线程 worker.interrupt(); } static class RunnableTask implements Runnable { public void run() { while (!Thread.currentThread().isInterrupted()) { // 执行任务 System.out.println("Thread is running..."); } } }
}
面试题3.53 volatile关键字的作用,能保证线程安全吗
【技术难度: 2 出现频率: 1 】
volatile关键字有两个作用,一是可以保证线程获取的数据是最新值(可见性),二是可以防止指令的重排序。它无法保证线程的安全性。
扩展(无需背诵):
当一个共享变量被 volatile 修饰时,它能保证修改的值会立即被更新到主内存,当有其他线程需要读取时,会去主内存中读取新值。
面试题3.54 Java 中 ++ 操作符是线程安全的吗?
【技术难度: 2 出现频率: 1 】
不是。它涉及到多个指令,如读取变量值,增加,然后存储回内存,并不是原子性的操作,这个过程可能会出现多个线程交差。
一个解决方案是对有i++操作的方法加同步锁。另一个解决方案是使用支持原子操作的类,比如AtomicInteger(java.util.concurrent.atomic.AtomicInteger)。
面试题3.55 请说说ThreadLocal?请说说线程本地变量?请说说本地线程?
【技术难度: 2 出现频率:1 】
第一层:
ThreadLocal可以实现每⼀个线程都有⾃⼰的专属本地变量,创建了⼀个ThreadLocal变量之后,访问这个变量的每个线程都会有这个变量的本地副本。他们可以使⽤get()和set()⽅法来获取或修改当前线程所存的值,从⽽避免线程安全问题。
第二层:
每个线程的本地变量并不是存放在ThreadLocal实例中,而是放在线程对象自己的threadLocals变量中,也就是说,ThreadLocal本地变量是存放在具体的线程空间上,所以不使用本地变量的时候需要调用remove方法删除不用的本地变量(不影响其他线程),否则只要线程不终止那这些不用的变量就会一直存活在线程对象中。
面试题3.56 死锁的原因
【技术难度: 1 出现频率: 1 】
当两个或两个以上的线程(或进程)在执行过程中,互相争夺对方持有的互斥资源,又不释放自己持有的锁资源,造成互相一直等待,此时若无外力作用,它们都将无法推进下去,这就是死锁。
面试题3.57 死锁与活锁的区别,死锁与饥饿的区别?
【技术难度: 3 出现频率:1 】
死锁和活锁的区别在于:处于活锁的线程是在不断的改变状态,就是所谓的“活”,而
处于死锁的线程表现为一直等待,活锁有可能自行解开,死锁则不能。
死锁与饥饿的区别在于,死锁除非外力无法解开,饥饿能够被解开,比如当其他高优先级的进程都终止时并且没有更高优先级的进程到达。
死锁、活锁、饥饿基本概念:
1.死锁:是指两个或两个以上的线程(或进程)在执行过程中,因争夺锁资源而造成
的一种互相等待的现象(卡住了),若无外力作用,它们都将无法推进下去。
2.活锁:任务或者执行者没有被阻塞,由于某些条件没有满足,导致一直重复尝试,
失败,尝试,失败。
3.饥饿:一个或者多个线程因为种种原因无法获得所需要的资源,导致一直无法执
行的状态。比如cpu一直给你分到调度。或一直wait,
产生死锁的必要条件:
1.互斥条件:所谓互斥就是进程在某一时间内独占资源。
2.请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
3.不剥夺条件:进程已获得资源,在末使用完之前,不能强行剥夺。
4.等待循环条件:若干进程之间形成一种头尾相接的循环等待资源关系。
Java中导致饥饿的原因:
1.高优先级线程吞噬所有的低优先级线程的 CPU 时间。
2.线程被永久堵塞在一个等待进入同步块的状态,因为其他线程总是能在它之前
持续地对该同步块进行访问。
3.线程在等待一个本身也处于永久等待完成的对象(比如调用这个对象的 wait 方
法),因为其他线程总是被持续地获得唤醒。
面试题3.58 java多线程有几种实现方式?你推荐哪一种
【技术难度:2 出现频率:2 】
有四种,分别是:
1.继承Thread类,重写run()方法;
2.实现Runnable接口,重写run()方法,这种最常用;
3.实现Callable接口,重写call()方法;(FutureTask对象的get()方法)
4.线程池。
推荐使用线程池 因为线程池中的线程可以循环使用。
面试题3.59 线程池的优点?
【技术难度: 2 出现频率:2 】
1.可重复使用已有线程;(池化的优点)
2.可有效控制最大并发线程数;
3.提供定时执行、定期执行、单线程、并发数控制等多种功能。
面试题3.60 什么是线程池?有哪几种创建方式?四种线程池的创建方式?
【技术难度: 2 出现频率:2 】
线程池用来管理多个线程,可以先创建好若干线程,使用时直接获取,以空间换时间的方式,提高线程的使用效率。(事先开好,直接从内存中申请,而不需要向系统申请)
线程池创建方式:
- Executors.newCachedThreadPool():创建 可以根据需要创建新线程 的线程池,不够创建,够用了回收,无限大;
- Executors.newFixedThreadPool(n); 创建可重用固定线程数的线程池,如果超过了需要等待;
- ScheduledExecutorService ses = Executors.newScheduledThreadPool(n):创建可周期定长线程池,它可延迟运行或周期执行;【延迟操作是子类自己的方法,所以不能用父类对象来引用】
- Executors.newSingleThreadExecutor() :创建只有一个线程的线程池。
或者创建自定义线程池,根据需求指定线程池参数。
面试题3.61 HashMap如何实现线程安全? ConcurrentHashMap和Hashtable的区别?
【技术难度: 2 出现频率: 1 】
第一层:
- 使用ConcurrentHashMap,它只锁住要修改的部分;
- 使用Collections类的synchronizedMap()方法包装一下,这种方式获得的线程安全的HashMap在读写数据的时候会对整个容器上锁,效率低下;
- Hashtable读写数据的时候会对整个容器上锁,效率低下。
推荐使用ConcurrentHashMap。
第二层:
ConcurrentHashMap在jdk1.7之前使用分段锁,将数据分段加不同对象锁,jdk1.8开始它用数组中每个头节点作为锁对象来使用synchronized锁,并使用CAS操作来进一步提高效率
扩展(无需背诵):
代码:
Map<Long,Object> map2 = new ConcurrentHashMap<>();
Map<Long,Object> map1 = Collections.synchronizedMap(new HashMap<Long,Object>());
Map<Long, String> map = new Hashtable<>();
------------------------END-------------------------
才疏学浅,谬误难免,欢迎各位批评指正。
相关文章:
Java全栈经典面试题剖析8】JavaSE高级 -- 线程同步、 线程通信、死锁、线程池
目录 面试题3.44 多线程的同步方式 面试题3.45 多线程安全问题怎么解决 面试题3.46 当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法? 面试题3.47 简述synchronized与java.util.concurrent.locks.Lock的异同ÿ…...

linux 驱动, struct file , struct node, private_data
首先是关于什么是 praviate_data : 来看看正点原子是怎么使用的。 网上找的一些资料: 总结一下: 1 私有数据 是 struct file特有的。 2private_data 可以自己随便设置。 3 一般是在 open 函数中设置好,然后在 read, write 函…...
ubuntu 硬盘扩容
在 Linux 中,可以使用以下命令查看磁盘的使用情况和信息: 查看磁盘使用情况: df -h这个命令会显示所有文件系统的使用情况,以人类可读的格式(例如 GB 或 MB)。 查看磁盘分区和设备信息: lsblk这…...

cm211-1刷机教程镜像包
cm211-1刷机教程 包含镜像包酷看桌面 s905l3-l3b通用 镜像包:https://www.123684.com/s/WGAwjv-5tlv3 1.刷机教程 镜像为线刷镜像包,需要短接刷机 短接刷机,导入镜像包 开始即可。到100%就证明可以了。...

Android 15自定义设置导航栏与状态栏,EdgeToEdge适配
背景:android api 35,activity设置EdgeToEdge.enable((ComponentActivity) this)前提下 一、设置导航栏与状态栏颜色 设置的状态栏颜色,只需要设置fitsSystemWindows跟setOnApplyWindowInsetsListener xml设置: 代码:…...
设计模式概览
设计模式是一种在软件设计中被广泛使用的解决方案,旨在提高软件的可重用性、可维护性和可扩展性。设计模式可以分为三大类:创建型、结构型和行为型。 1、创建型模式 这些模式主要关注对象的创建过程,提供了不同的方式来创建对象,…...
力扣每日一题打卡 684. 冗余连接
树可以看成是一个连通且 无环 的 无向 图。 给定往一棵 n 个节点 (节点值 1~n) 的树中添加一条边后的图。添加的边的两个顶点包含在 1 到 n 中间,且这条附加的边不属于树中已存在的边。图的信息记录于长度为 n 的二维数组 edges ,edges[i] …...

什么是微服务中的反应性扩展?
大家好,我是锋哥。今天分享关于【什么是微服务中的反应性扩展?】面试题?希望对大家有帮助; 什么是微服务中的反应性扩展? Reactive Extensions 也称为 Rx。这是一种设计方法,我们通过调用多个服务来收集结果…...

【MyBatis】MyBatis-config标签详解
目录 MyBatis配置文件标签详解configuration标签properties标签typeAliases标签environments标签environment标签transactionManager标签dataSource标签mappers标签 MyBatis配置文件标签详解 我们在使用MyBatis框架的时候需要一个配置文件——MyBatis-config.xml来告诉MyBatis…...
使用AVPlayer进行音频播放开发基础设计
在使用AvPlayer进行设计之前,需要获取相应对象,后期围绕该对象展开操作 const player await media.createAVPlayer() 然后对播放器进行初始化设置: player.on(stateChange, (state) > {switch (state) {case initialized:player.prepar…...

API网关的作用--为什么微服务需要一个API网关?
微服务网关核心作用就是协议转换、安全隔离和流量控制 微服务架构中,API网关作为系统的入口点,可以统一处理所有客户端请求。 1)协议转换:它能够支持多种通信协议(如HTTP、gRPC等)之间的相互转换ÿ…...

[0154].第5节:IDEA中创建Java Web工程
我的后端学习大纲 IDEA大纲 1.1.IDEA中配置Tomcat: 1.找打setting: 2.配置Tomcat Server的位置: 3.这里配置Tomcat的名称以及配置应用服务器的位置。根据自己Tomcat的安装位置决定 4.配置好后,如下图所示 1.2.创建Web工程: 1.建…...
React03 组件 Props
组件 & Props React 组件函数( Function )组件类( Class )组件 Props将 props 传递给子组件在子组件中读取 props给 prop 指定一个默认值使用 JSX 展开语法传递 props React 组件 组件本质上就是类和函数,但是与常…...

多线程——线程安全的集合类
目录 前言 一、多线程环境使用 ArrayList 1.进行加锁 2.使用 SynchronizedList 类 3.使用 CopyOnWriteArrayList 类 二、多线程环境使用队列 1.进行加锁 2.使用阻塞队列 三、多线程环境使用哈希表 1.Hashtable 2.ConcurrentHashMap (1)缩小锁…...
自动化数据库管理:如何通过存储过程动态创建 MySQL 对象
在当今数据驱动的世界中,高效的数据库管理至关重要。本文将展示如何通过存储过程自动化地创建各种 MySQL 数据库对象,包括数据表、视图、字段、索引、约束、存储过程、定时器和事件。通过这些方法,我们可以快速响应业务需求,提高数…...

480p 720p 1080p 2k 4k 8k 12k分辨率视频分别占用多大带宽?
技术背景 好多开发者,在设置视频编码参数的时候,对不同分辨率的带宽设置,缺乏相关的经验,实际上,视频分辨率与所需带宽之间的关系受到多个因素的影响,包括视频编码方式、帧率、视频内容的动态程度等。下面…...

unity中GameObject介绍
在 Unity 中,Cube和Sphere等基本几何体是 Unity 引擎的内置预制体(Prefabs),它们属于 Unity 中的GameObject 系统,可以在 Unity 的 Hierarchy 视图或 Scene 视图中右键点击,然后在弹出的菜单中选择 3D Obje…...

洛谷——P8468 [Aya Round 1 C] 文文的构造游戏(01构造问题)
P8468 [Aya Round 1 C] 文文的构造游戏 题目描述 [Aya Round 1 C] 文文的构造游戏 - 洛谷 运行代码(暴力枚举)——超时 #include <stdio.h> #define ll long long const int N 1e6 5; // 计算数组元素的异或和 ll xorSum(ll arr[], int n) {l…...
双击热备和负载均衡的区别
区别: 双机热备 (heartbeat):对同一应用来讲,永远是主机应用启动,备机应用停止的一主一备模式(两台通常叫双击热备,多台称为高可用) 负载均衡:两台/多台服务器 上同一个应用系统同时工作,分担负…...

如何使用 cPanel 部署 WordPress临时网站
对于依赖WordPress站点或WooCommerce商店的企业来说,在生产环境中直接修改站点风险很大。而WordPress的临时网站是一个更安全的选择,可以通过使用临时网站进行编辑来规避风险。 在本文中,我们将详细介绍WordPress临时网站的相关知识、使用临时…...
OpenLayers 可视化之热力图
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 热力图(Heatmap)又叫热点图,是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...
基于Uniapp开发HarmonyOS 5.0旅游应用技术实践
一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架,支持"一次开发,多端部署",可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务,为旅游应用带来…...
测试markdown--肇兴
day1: 1、去程:7:04 --11:32高铁 高铁右转上售票大厅2楼,穿过候车厅下一楼,上大巴车 ¥10/人 **2、到达:**12点多到达寨子,买门票,美团/抖音:¥78人 3、中饭&a…...

P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...

全志A40i android7.1 调试信息打印串口由uart0改为uart3
一,概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本:2014.07; Kernel版本:Linux-3.10; 二,Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01),并让boo…...

C/C++ 中附加包含目录、附加库目录与附加依赖项详解
在 C/C 编程的编译和链接过程中,附加包含目录、附加库目录和附加依赖项是三个至关重要的设置,它们相互配合,确保程序能够正确引用外部资源并顺利构建。虽然在学习过程中,这些概念容易让人混淆,但深入理解它们的作用和联…...
LRU 缓存机制详解与实现(Java版) + 力扣解决
📌 LRU 缓存机制详解与实现(Java版) 一、📖 问题背景 在日常开发中,我们经常会使用 缓存(Cache) 来提升性能。但由于内存有限,缓存不可能无限增长,于是需要策略决定&am…...
Linux系统部署KES
1、安装准备 1.版本说明V008R006C009B0014 V008:是version产品的大版本。 R006:是release产品特性版本。 C009:是通用版 B0014:是build开发过程中的构建版本2.硬件要求 #安全版和企业版 内存:1GB 以上 硬盘…...
安卓基础(Java 和 Gradle 版本)
1. 设置项目的 JDK 版本 方法1:通过 Project Structure File → Project Structure... (或按 CtrlAltShiftS) 左侧选择 SDK Location 在 Gradle Settings 部分,设置 Gradle JDK 方法2:通过 Settings File → Settings... (或 CtrlAltS)…...