java中的锁面试题

1、多线程中 synchronized 锁升级的原理是什么?

synchronized 是JVM层面的锁,是 Java 关键字,通过 monitor 对象来完成,synchronized 的实现涉及到锁的升级,具体为无锁、偏向锁、自旋锁、重量级锁
synchronized 锁升级原理:在锁对象的对象头里面有一个 threadid 字段,在第一次访问的时候 threadid 为空,jvm 让其持有偏向锁,并将 threadid 设置为其线程 id,再次进入的时候会先判断 threadid 是否与其线程 id 一致,如果一致则可以直接使用此对象,如果不一致,则升级偏向锁为轻量级锁(只要有另一个竞争线程就升级),通过自旋循环一定次数来获取锁,执行一定次数之后,如果还没有正常获取到要使用的对象,此时就会把锁从轻量级升级为重量级锁,此过程就构成了 synchronized 锁的升级。

锁的升级的目的:锁升级是为了减低了锁带来的性能消耗。在 Java 6 之后优化 synchronized 的实现方式,使用了偏向锁升级为轻量级锁再升级到重量级锁的方式,从而减低了锁带来的性能消耗。

升级成重量锁条件

老版本:2个条件

  • 第一个条件,自旋次数超过10次时直接升级为重量级,就是转圈赚了10次后直接升级重量级锁,jvm有个参数 preSpinLock,默认是10次,可以自己设置
  • 第二个条件,如果自旋线程的数量超过了cpu的二分之一,也会直接升级为重量级锁;比如你的cpu锁核数是8个,但是有5个线程在那自旋等着占锁使用,8的二分之一是4,5个线程明显已经超过了4,所以这时候直接升级为重量级锁;

新版本:Adaptive CAS (自适应自旋),让hotSpot自己决定自旋几次在升级为重量级锁,就相当于自动化了;也就不用我们去管了。所以以后jvm调优就不需要调整自旋次数的参数;因为内部情况怎样只有jvm自己知道;

2、Synchronized 与 ReentrantLock 的区别

1.1 底层实现的区别

  • synchronized 是JVM层面的锁,是 Java 关键字,通过 monitor 对象来完成,synchronized 的实现涉及到锁的升级,具体为无锁、偏向锁、自旋锁、重量级锁
  • 而 ReentrantLock 是由 java api 去实现的。ReentrantLock 实现则是通过利用CAS自旋机制保证线程操作的原子性和volatile保证数据可见性以实现锁的功能。

1.2 是否可手动释放

  • synchronized 不需要用户去手动释放锁,synchronized 代码执行完后系统会自动让线程释放对锁的占用。
  • ReentrantLock 则需要用户去手动释放锁,如果没有手动释放锁,就可能导致死锁现象。一般通过 lock() 和 unlock() 方法配合 try / finally 语句块来完成,使用释放更加灵活。

1.3 是否可中断

  • synchronized 是不可中断类型的锁,除非加锁的代码中出现异常或正常执行完成。
  • ReentrantLock 则可以中断,可通过 trylock(long timeout,TimeUnit unit) 设置超时方法;或者将 lockInterruptibly() 放到代码块中,调用 interrupt 方法进行中断。

1.4 是否公平锁

  • synchronized 为非公平锁。
  • ReentrantLock 则即可以选公平锁也可以选非公平锁,通过构造方法 new ReentrantLock 时传入 boolean 值进行选择,为空默认 false 非公平锁,true 为公平锁。

1.5 锁是否可绑定条件 Condition

  • synchronized 不能绑定。
  • ReentrantLock 通过绑定 Condition 结合 await() / singal() 方法实现线程的精确唤醒,而不是像 synchronized 通过 Object 类的 wait() / notify() / notifyAll() 方法要么随机唤醒一个线程要么唤醒全部线程。

1.6 锁的对象

  • synchronzied 锁的是对象,锁是保存在对象头里面的,根据对象头数据来标识是否有线程获得锁 / 争抢锁。
  • ReentrantLock 锁的是线程,根据进入的线程和 int 类型的 state 标识锁的获得 / 争抢。

原文链接:https://blog.csdn.net/liuwg1226/article/details/120164119

3、synchronized和lock有什么区别

  • 1:synchronized 是JVM层面的锁,是 Java 关键字,通过 monitor 对象来完成,synchronized 的实现涉及到锁的升级,具体为无锁、偏向锁、自旋锁、重量级锁,而Lock是java.util.concurrent.Locks 包下的一个接口;
  • 2:Synchronized 使用过后,会自动释放锁,而Lock需要手动上锁、手动释放锁。(在 finally 块中)
  • 3:synchronized 关键字不能响应中断;Lock可以响应中断、可定时
  • 4:synchronized关键字是非公平锁,即,不能保证等待锁的那些线程们的顺序,而Lock的子类ReentrantLock默认是非公平锁,但是可通过一个布尔参数的构造方法实例化出一个公平锁;
  • 5:synchronized无法判断,是否已经获取到锁,而Lock通过tryLock()方法可以判断,是否已获取到锁;
  • 6:Lock可以通过分别定义读写锁提高多个线程读操作的效率。
  • 7:二者的底层实现不一样:synchronized是同步阻塞,采用的是悲观并发策略;Lock是同步非阻塞,采用的是乐观并发策略(底层基于volatile关键字和CAS算法实现)

4、公平锁、非公平锁、可重入锁、独占锁

  • 公平锁是指在分配时候考虑线程排队等待的情况,优先将该锁分配给排队时间最长的线程
  • 非公平锁指在分配时候不考虑线程排队等待的情况,直接尝试获得锁,在获取不到锁时候再排队,到队尾等待
  • 可重入锁也叫递归锁,指在同一个线程中,在外层函数获得该锁之后,内层的递归函数依旧可以继续获取该锁
  • 独占锁指该锁在同一个时间只能被同一个线程获得,而获得锁的其他线程只能在同步队列中等待

5、Volatile如何保证可见性

Volatile有两个特性:

  • 一种是保证该变量对所有的线程可见
  • 一种是禁止指令重排,即Volatile变量不会被缓存在寄存器或是对其他处理器不可见的地方

volatile修饰的变量,JMM将在写操作后插入一个写屏障指令,在读操作前插入一个读屏障指令,这代表着:

  • 一旦对变量写入了新值,任何访问这个变量的线程都会得到新的值
  • 在写入前,也会保证所有之前发生的事情已经发生,并且更新过的数据值也是可见的。内存屏障会把之前的写入值都刷新到主内存

所以Volatile可以保证可见性

6、说说java内存模型

java内存模型(JMM)是线程间通信的控制机制.JMM定义了主内存和线程之间抽象关系。线程之间的共享变量存储在主内存中,每个线程都有一个私有的本地内存,本地内存中存储了该线程以读/写共享变量的副本。本地内存是JMM的一个抽象概念,并不真实存在。它涵盖了缓存,写缓冲区,寄存器以及其他的硬件和编译器优化。

7、死锁的发生原因和怎么避免

死锁,简单来说就是两个或者两个以上的线程在执行的过程中,争夺同一个共享资源造成的相互等待的现象。如果没有外部干预,线程会一直阻塞无法往下执行,这些一直处于相互等待资源的线程就称为死锁线程。

导致死锁的条件有四个,也就是这四个条件同时满足就会产生死锁。

  • 互斥条件,共享资源 X 和 Y 只能被一个线程占用;
  • 请求和保持条件,线程 T1 已经取得共享资源 X,在等待共享资源 Y 的时候,不释放共享资源 X;
  • 不可抢占条件,其他线程不能强行抢占线程 T1 占有的资源;
  • 循环等待条件,线程 T1 等待线程 T2 占有的资源,线程 T2 等待线程 T1 占有的资源,就是循环等待。

按照死锁发生的四个条件,只需要破坏其中的任何一个,就可以解决,但是,互斥条件是没办法破坏的,因为这是互斥锁的基本约束,其他三方条件都有办法来破坏:

1、设置超时时间,超时可以退出,防止死锁

2、降低锁的使用粒度,尽量不要几个功能用同一把锁

3、我们可以一次性申请所有的资源,这样就不存在等待了

8、CAS、CAS自旋等待、ABA问题

CAS指比较并交换,CAS算法CAS(V,E,N)包含三个参数,V表示要更新的变量 E 表示预期的值 N 表示 新值。当要更新的变量等于预期的值,才会把要更新的变量设置为新值,CAS操作采用了乐观锁的思想

CAS自旋等待:在原子包concurrent提供了一组原子类,这些原子类的基本特性是在多线程的环境下,在有多个线程同时执行这些类的实列包含的方法时候,会有排他性。其内部便是基于CAS算法实现的,即在某个线程进入方法中执行其中的指令时候,不会被其他线程打断,而别的线程就像自旋锁一样,一直等到该方法执行完才由jvm从等待的队列中选择另外一个线程进入。

ABA问题:在需要取出内存中某时刻的数据,然后再下一个时候进行比较替换,如果在这个时间差内可能数据已经发生改变,可能导致ABA问题。即第1个线程从V取出A,这时第2个线程也从内存V中取出A,并将V位置的数据A先修改成B,接着又把数据修改成A ,第一个线程在进行CAS操作的时候发现V位置的数据是A,第一个线程操作成功。尽管第一个线程角度,CAS操作是成功,但实际上的数据发生了变化,某些情况下可能引起过程数据不一致的问题。可以通过版本号来解决这个问题

9、什么是AQS

AQS是一个抽象的队列同步器,通过维护一个共享的资源状态和一个先进先出的线程等待队列来实现一个多线程访问共享资源的同步框架

AQS为每个共享资源都设置了一个共享资源锁,线程在需要访问共享资源时首先需要获得共享资源锁,如果获取到了共享资源锁,既可以在当前线程使用该共享资源,如果获取不到,则将该线程放入等待队列中,等待下次调度

AQS定义了两种资源共享的方式,独占式和共享式

  • 独占式:只有一个线程可以执行,如ReentrantLock,原理是ReentrantLock中的state初始值为0表示无锁状态,在线程执行tryAcquire()获取该锁后state+1,这是该线程独占ReentrantLock锁,其他线程在通过tryAcquire()获得锁时候都会失败,直到该线程释放后state再次为0
  • 共享式多个线程可以同时执行,如countDownLatch等

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

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

相关文章

C++的 I/O 流

本文把复杂的基类和派生类的作用和关系捋出来,具体的接口请参考相关文档 C的 I/O 流相关的类,继承关系如下图所示 https://zh.cppreference.com/w/cpp/io I / O 的概念:内存和外设进行数据交互称为 I / O ,例如:把数…

【HarmonyOS之旅】基于ArkTS开发(三) -> 兼容JS的类Web开发(四) -> 常见组件(一)

目录 1 -> List 1.1 -> 创建List组件 1.2 -> 添加滚动条 1.3 -> 添加侧边索引栏 1.4 -> 实现列表折叠和展开 1.5 -> 场景示例 2 -> dialog 2.1 -> 创建Dialog组件 2.2 -> 设置弹窗响应 2.3 -> 场景示例 3 -> form 3.1 -> 创建…

《Python预训练视觉和大语言模型》:从DeepSeek到大模型实战的全栈指南

就是当代AI工程师的日常:* - 砸钱买算力,却卡在分布式训练的“隐形坑”里; - 跟着论文复现模型,结果连1/10的性能都达不到; - 好不容易上线应用,却因伦理问题被用户投诉…… 当所有人都在教你怎么调用…

【Elasticsearch】date range聚合

好的,继续之前的示例: json ] } } } } 4.3 自定义键(key) 通过为每个范围指定一个唯一的键(key),可以在结果中更方便地引用每个范围。这在使用keyed参数将结果以键值对形式返回时尤其有用。 j…

ElasticSearch 学习课程入门(二)

引子 前文已经介绍了ES的增删改查基本操作,接下来,我们学习下高级点的用法。OK,那就让我们开始吧。 一、ES高级操作 1、条件查询 (1)GET https://127.0.0.1:9200/shopping/_search?qcategory:小米 (2&…

6.PPT:魏女士-高新技术企业政策【19】

目录 NO1234​ NO567 ​ NO1234 创建“PPT.pptx”考生文件夹Word素材文档:选中对应颜色的文字→选中对应的样式单击右键按下匹配对应文字:应用所有对应颜色的文字开始→创建新的幻灯片→从大纲:考生文件夹:Word素材重置 开始→版…

【Linux系统】信号:信号保存 / 信号处理、内核态 / 用户态、操作系统运行原理(中断)

理解Linux系统内进程信号的整个流程可分为: 信号产生 信号保存 信号处理 上篇文章重点讲解了 信号的产生,本文会讲解信号的保存和信号处理相关的概念和操作: 两种信号默认处理 1、信号处理之忽略 ::signal(2, SIG_IGN); // ignore: 忽略#…

【算法篇】贪心算法

目录 贪心算法 贪心算法实际应用 一,零钱找回问题 二,活动选择问题 三,分数背包问题 将数组和减半的最小操作次数 最大数 贪心算法 贪心算法,是一种在每一步选择中都采取当前状态下的最优策略,期望得到全局最优…

SSM网上球鞋竞拍系统

🍅点赞收藏关注 → 添加文档最下方联系方式咨询本源代码、数据库🍅 本人在Java毕业设计领域有多年的经验,陆续会更新更多优质的Java实战项目希望你能有所收获,少走一些弯路。🍅关注我不迷路🍅 项目视频 js…

基于springboot河南省旅游管理系统

基于Spring Boot的河南省旅游管理系统是一种专为河南省旅游行业设计的信息管理系统,旨在整合和管理河南省的旅游资源信息,为游客提供准确、全面的旅游攻略和服务。以下是对该系统的详细介绍: 一、系统背景与意义 河南省作为中国的中部省份&…

人工智能|本地部署|ollama+chatbox快速Windows10下部署(初级篇)

一、 前言: 其实早一个月我已经使用过deepseek,并且也在自己的机器上通过ollama部署过,但一直没有太多动力,现在感觉还是的记录一下,省的自己给忘掉了 本文只是简单记录一下ollamaopen-webuichatbox部署通过网盘分享…

ZZNUOJ(C/C++)基础练习1061——1070(详解版)

目录 1061 : 顺序输出各位数字 C语言版 C版 1062 : 最大公约数 C C 1063 : 最大公约与最小公倍 C C 1064 : 加密字符 C C 1065 : 统计数字字符的个数 C C 1066 : 字符分类统计 C C 1067 : 有问题的里程表 C C 1068 : 进制转换 C C C(容器stack…

记录一下 在Mac下用pyinstallter 打包 Django项目

安装: pip install pyinstaller 在urls.py from SheepMasterOneToOne import settings from django.conf.urls.static import staticurlpatterns [path("admin/", admin.site.urls),path(generate_report/export/, ReportAdmin(models.Report, admin.site).generat…

使用Python和TensorFlow/Keras构建一个简单的CNN模型来识别手写数字

一个简单的图像识别项目代码示例,使用Python和TensorFlow/Keras库来训练一个基本的CNN模型,用于识别MNIST手写数字数据集,并将测试结果输出到HTML。 代码运行效果截图: 具体操作步骤: 1. 安装所需的库 首先,确保你已经安装了所需的Python库: pip install tensorflow…

2021.3.1的android studio版本就很好用

使用最新版的studio有个问题就是gradle版本也比较高,这样就容易出现之前项目不兼容问题,配置gradle可能会出现很多问题比较烦,所以干脆就用老版本的studio

控件【QT】

文章目录 控件QWidgetenabledgeometrysetGeometry qrcwindowOpacityQPixmapfonttoolTipfocusPolicystyleSheetQPushButtonRadio ButtionCheck Box显示类控件QProgressBarcalendarWidget 控件 Qt中已经提供了很多内置的控件了(按钮,文本框,单选按钮,复选按钮,下拉框…

【小鱼闪闪】做一个物联网控制小灯的制作流程简要介绍(图文)

1、注册物联网云平台,这里选用巴法云 2.、新建主题 “ledtest” 3、 使用Arduino或Mixly软件编写单片机程序(需要引用巴法云库文件),程序中订阅“ledtest”主题,用于接收单片机发送来的数据。此处会将连接的温度传感器…

KNN算法:从思想到实现(附代码)

引言 K最近邻算法(K Nearest Neighbors, KNN)是一种简单而有效的机器学习算法,用于分类和回归问题。其核心思想基于“近朱者赤,近墨者黑”,即通过测量不同特征值之间的距离来进行分类或预测数值。本文将详细介绍KNN的…

专业学习|一文了解并实操自适应大邻域搜索(讲解代码)

一、自适应大邻域搜索概念介绍 自适应大邻域搜索(Adaptive Large Neighborhood Search,ALNS)是一种用于解决组合优化问题的元启发式算法。以下是关于它的详细介绍: -自适应大领域搜索的核心思想是:破坏解、修复解、动…

TensorFlow深度学习实战(6)——回归分析详解

TensorFlow深度学习实战(6)——回归分析详解 0. 前言1. 回归分析简介2. 线性回归2.1 简单线性回归2.2 多重线性回归2.3 多元线性回归 3. 构建基于线性回归的神经网络3.1 使用 TensorFlow 进行简单线性回归3.2 使用 TensorFlow 进行多元线性回归和多重线性…