当前位置: 首页 > news >正文

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等

相关文章:

java中的锁面试题

1、多线程中 synchronized 锁升级的原理是什么? synchronized 是JVM层面的锁,是 Java 关键字,通过 monitor 对象来完成,synchronized 的实现涉及到锁的升级,具体为无锁、偏向锁、自旋锁、重量级锁 synchronized 锁升级…...

ES6 变量解构赋值总结

1. 数组的解构赋值 1.1 基本用法 // 基本数组解构 const [a, b, c] [1, 2, 3]; console.log(a); // 1 console.log(b); // 2 console.log(c); // 3// 跳过某些值 const [x, , y] [1, 2, 3]; console.log(x); // 1 console.log(y); // 3// 解构剩余元素 const [first, ...re…...

知识蒸馏教程 Knowledge Distillation Tutorial

来自于:Knowledge Distillation Tutorial 将大模型蒸馏为小模型,可以节省计算资源,加快推理过程,更高效的运行。 使用CIFAR-10数据集 import torch import torch.nn as nn import torch.optim as optim import torchvision.tran…...

DeepSeek各版本说明与优缺点分析

DeepSeek各版本说明与优缺点分析 DeepSeek是最近人工智能领域备受瞩目的一个语言模型系列,其在不同版本的发布过程中,逐步加强了对多种任务的处理能力。本文将详细介绍DeepSeek的各版本,从版本的发布时间、特点、优势以及不足之处&#xff0…...

java进阶专栏的学习指南

学习指南 java类和对象java内部类和常用类javaIO流 java类和对象 类和对象 java内部类和常用类 java内部类精讲Object类包装类的认识String类、BigDecimal类初探Date类、Calendar类、SimpleDateFormat类的认识java Random类、File类、System类初识 javaIO流 java IO流【…...

kamailio-osp模块

该文档详细讲解了如何在Kamailio中配置和使用OSP模块(Open Settlement Protocol Module),以实现基于ETSI标准的安全多边对等互联(Secure Multi-Lateral Peering)。以下是核心内容的总结: 1. 模块功能 OSP模…...

【TensorFlow】T1:实现mnist手写数字识别

🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍖 原作者:K同学啊 1、设置GPU import tensorflow as tf gpus tf.config.list_physical_devices("GPU")if gpus:gpu0 gpus[0]tf.config.experimental.set_memory_g…...

Rapidjson 实战

Rapidjson 是一款 C 的 json 库. 支持处理 json 格式的文档. 其设计风格是头文件库, 包含头文件即可使用, 小巧轻便并且性能强悍. 本文结合样例来介绍 Rapidjson 一些常见的用法. 环境要求 有如何的几种方法可以将 Rapidjson 集成到您的项目中. Vcpkg安装: 使用 vcpkg instal…...

【React】受控组件和非受控组件

目录 受控组件非受控组件基于ref获取DOM元素1、在标签中使用2、在组件中使用 受控组件 表单元素的状态(值)由 React 组件的 state 完全控制。组件的 state 保存了表单元素的值,并且每次用户输入时,React 通过事件处理程序来更新 …...

Ollama+deepseek+Docker+Open WebUI实现与AI聊天

1、下载并安装Ollama 官方网址:Ollama 安装好后,在命令行输入, ollama --version 返回以下信息,则表明安装成功, 2、 下载AI大模型 这里以deepseek-r1:1.5b模型为例, 在命令行中,执行&…...

DEEPSEKK GPT等AI体的出现如何重构工厂数字化架构:从设备控制到ERP MES系统的全面优化

随着深度学习(DeepSeek)、GPT等先进AI技术的出现,工厂的数字化架构正在经历前所未有的变革。AI的强大处理能力、预测能力和自动化决策支持,将大幅度提升生产效率、设备管理、资源调度以及产品质量管理。本文将探讨AI体&#xff08…...

阿莱(arri)mxf文件变0字节的恢复方法

阿莱(arri)是专业级的影视产品软硬件供应商,很多影视作品都是使用阿莱(arri)的设备拍摄出来的。总体上来讲阿莱(arri)的文件格式有mov和mxf两种,这次恢复的是阿莱(arri)的mxf,机型是arri mini,素材保存在一个8t的硬盘上,使用的是e…...

初识 Node.js

在当今快速发展的互联网技术领域,Node.js 已经成为了一个非常流行且强大的平台。无论是构建高性能的网络应用、实时协作工具还是微服务架构,Node.js 都展示了其独特的优势。本文将带您走进 Node.js 的世界,了解它的基本概念、核心特性以及如何…...

debug-vscode调试方法

debug - vscode gdb调试指南 文章目录 debug - vscode gdb调试指南前言一、调试代码二、命令查看main反汇编查看寄存器打印某个变量打印寄存器,如pc打印当前函数栈信息(当前执行位置)打印程序栈局部变量x命令的语法如下所示:打印某…...

Cypher进阶(函数、索引)

文章目录 Cypher进阶Aggregationcount()函数统计函数collect()函数 unwindforeachmergeunionload csvcall 函数断言函数all()any()~~exists()~~is not nullnone()single() 标量函数coalesce()startNode()/endNode()id()length()size() 列表函数nodes()keys()range()reduce() 数…...

XML Schema 数值数据类型

XML Schema 数值数据类型 引言 XML Schema 是一种用于描述 XML 文档结构的语言。它定义了 XML 文档中数据的有效性和结构。在 XML Schema 中,数值数据类型是非常重要的一部分,它定义了 XML 文档中可以包含的数值类型。本文将详细介绍 XML Schema 中常用的数值数据类型,以及…...

Window获取界面空闲时间

‌GetLastInputInfo‌是一种Windows API函数,用于获取上次输入操作的时间。 该函数通过LASTINPUTINFO结构返回最后一次输入事件的时间。 原型如下 BOOL WINAPI GetLastInputInfo(PLASTINPUTINFO plii);那么可以利用GetLastInputInfo来得到界面没有操作的时长 uint…...

Java进阶(vue基础)

目录 1.vue简单入门 ?1.1.创建一个vue程序 1.2.使用Component模板(组件) 1.3.引入AXOIS ?1.4.vue的Methods(方法) 和?compoted(计算) 1.5.插槽slot 1.6.创建自定义事件? 2.Vue脚手架安装? 3.Element-UI的…...

Mac电脑上好用的压缩软件

在Mac电脑上,有许多优秀的压缩软件可供选择,这些软件不仅支持多种压缩格式,还提供了便捷的操作体验和强大的功能。以下是几款被广泛推荐的压缩软件: BetterZip 功能特点:BetterZip 是一款功能强大的压缩和解压缩工具&a…...

Ubuntn24.04安装

1.镜像下载 https://cn.ubuntu.com/download Ubuntu 24.04.1 (Noble Numbat) 进入下载即可 2.安装系统 打开虚拟机 选择语言 输入用户名和密码 安装ssh 安装完成重启即可。 3.可能出现的问题 关于Ubuntu系统虚拟机出现频繁闪屏,移动和屏幕适应大小问题_vmware安…...

C++:std::is_convertible

C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来

一、破局&#xff1a;PCB行业的时代之问 在数字经济蓬勃发展的浪潮中&#xff0c;PCB&#xff08;印制电路板&#xff09;作为 “电子产品之母”&#xff0c;其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透&#xff0c;PCB行业面临着前所未有的挑战与机遇。产品迭代…...

可靠性+灵活性:电力载波技术在楼宇自控中的核心价值

可靠性灵活性&#xff1a;电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中&#xff0c;电力载波技术&#xff08;PLC&#xff09;凭借其独特的优势&#xff0c;正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据&#xff0c;无需额外布…...

PL0语法,分析器实现!

简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...

什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南

文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/55aefaea8a9f477e86d065227851fe3d.pn…...

Ubuntu系统复制(U盘-电脑硬盘)

所需环境 电脑自带硬盘&#xff1a;1块 (1T) U盘1&#xff1a;Ubuntu系统引导盘&#xff08;用于“U盘2”复制到“电脑自带硬盘”&#xff09; U盘2&#xff1a;Ubuntu系统盘&#xff08;1T&#xff0c;用于被复制&#xff09; &#xff01;&#xff01;&#xff01;建议“电脑…...

6个月Python学习计划 Day 16 - 面向对象编程(OOP)基础

第三周 Day 3 &#x1f3af; 今日目标 理解类&#xff08;class&#xff09;和对象&#xff08;object&#xff09;的关系学会定义类的属性、方法和构造函数&#xff08;init&#xff09;掌握对象的创建与使用初识封装、继承和多态的基本概念&#xff08;预告&#xff09; &a…...

es6+和css3新增的特性有哪些

一&#xff1a;ECMAScript 新特性&#xff08;ES6&#xff09; ES6 (2015) - 革命性更新 1&#xff0c;记住的方法&#xff0c;从一个方法里面用到了哪些技术 1&#xff0c;let /const块级作用域声明2&#xff0c;**默认参数**&#xff1a;函数参数可以设置默认值。3&#x…...

第八部分:阶段项目 6:构建 React 前端应用

现在&#xff0c;是时候将你学到的 React 基础知识付诸实践&#xff0c;构建一个简单的前端应用来模拟与后端 API 的交互了。在这个阶段&#xff0c;你可以先使用模拟数据&#xff0c;或者如果你的后端 API&#xff08;阶段项目 5&#xff09;已经搭建好&#xff0c;可以直接连…...

[特殊字符] 手撸 Redis 互斥锁那些坑

&#x1f4d6; 手撸 Redis 互斥锁那些坑 最近搞业务遇到高并发下同一个 key 的互斥操作&#xff0c;想实现分布式环境下的互斥锁。于是私下顺手手撸了个基于 Redis 的简单互斥锁&#xff0c;也顺便跟 Redisson 的 RLock 机制对比了下&#xff0c;记录一波&#xff0c;别踩我踩过…...