首页 > 编程语言 >面试篇-Java-1+锁+AQS+死锁

面试篇-Java-1+锁+AQS+死锁

时间:2024-07-14 10:55:16浏览次数:20  
标签:Synchronized Java 1.1 AQS CAS 死锁 线程 volatile

文章目录


前言

你们在项目中高并发时你都用过哪些锁,它的原理是什么;你知道类加载的过程,双亲委派机制吗;你们有用到过线程池吗,它的工作过程是怎样的。本文重点对面试的问题进行介绍,祝愿每位程序员都能顺利上岸!!!


一、并发编程中你都用过哪些锁

1.1 Synchronized【对象锁】

1.1.1 Synchronized的使用

Synchronized【对象锁】采用互斥的方式让同一时刻至多只有一个线程能持有【对象锁】,其它线程再想获取这个【对象锁】时就会阻塞住.具体的使用场景可以参考: 还在为Synchronized烦恼吗?那么请移步Java并发编程数据安全之Synchronized篇

在这里插入图片描述

1.1.2 你知道Synchronized的原理吗

被Synchronized 关键字修饰的方法,代码块,在编译后的class 文件后,会通过monitorenter为对象上锁,通过monitorexit 释放锁,来实现排它锁。

在这里插入图片描述

1.1.2.1 你知道monitor 的结构

monitor 数据结构中保存了当前获取所得线程,和等待去获取所得线程

在这里插入图片描述

1.1.3 Synchronized 的实现原理

  • Synchronized【对象锁】采用互斥的方式让同一时刻至多只有一个线程能持有【对象锁】
  • 它的底层由monitor实现的,monitor是jvm级别的对象(C++实现)线程获得锁需要使用对象(锁)关联monitor
  • 在monitor内部有三个属性,分别是owner、entrylist、waitset
  • 其中owner是关联的获得锁的线程,并且只能关联一个线程
  • ;entrylist关联的是处于阻塞状态的线程;
  • waitset关联的是处于Waiting状态的线程

1.1.3 你知道Synchronized 锁的升级吗

monitor 实现了重量级锁,只有发生并发资源的抢占,就会当前未抢到锁的线程,放入到阻塞队列中,里面涉及到了用户态和内核态的切换、进程的上下文切换,成本较高,性能比较低。在JDK1.6引入了两种新型锁机制:偏向锁和轻量级锁,它们的引入是为了解决在没有多线程竞争或基本没有竞争的场景下因使用传统锁机制带来的性能开销问题。引入了偏向锁和轻量级锁 此时锁的实现是怎样的呢;

1.1.3.1 你知道对象头的内存结构和对象头的结构吗

在这里插入图片描述

对象头的结构
在这里插入图片描述

1.1.3.2 偏向锁

线程1 进入,发现此时无锁,通过CAS 操作将线程1的id 设置到对象头中,并且将锁的标记设置为偏向锁;一段很长的时间内都只被一个线程使用锁,可以使用了偏向锁,在第一次获得锁时,会有一个CAS操作,之后该线程再获取锁,只需要判断mark word中是否是自己的线程id即可,而不是开销相对较大的CAS命令。

在这里插入图片描述

1.1.3.2 轻量级锁

线程2此时进入,进入后发现为偏向锁,则通过CAS操作 将线程2的id 设置到对象头中;CAS 成果则获取到锁,如果CAS 失败,则进行偏向锁的撤销,并将锁升级为轻量级锁;线程加锁的时间是错开的(也就是没有竞争),可以使用轻量级锁来优化。轻量级修改了对象头的锁标志,相对重量级锁性能提升很多。每次修改都是CAS操作,保证原子性。

在这里插入图片描述

1.1.3.3 重量级锁

线程2 则通过CAS 操作将对象头的Markword设置为指向该帧中保存的markword副本,如果设置成功,则说明成功获取锁,如果获取失败,则自旋等待获取锁(当自旋多次依旧没有获取到锁时。会将轻量级锁升级为重量级锁(设置对象的锁标记为重量级锁))底层使用的Monitor实现,里面涉及到了用户态和内核态的切换、进程的上下文切换,成本较高,性能比较低。

二、你知道CAS 吗

CAS的全称是:Compare And Swap(比较再交换),它体现的一种乐观锁的思想,在无锁情况下保证线程操作共享数据的原子性。因为没有加锁,所以线程不会陷入阻塞,效率较高;如果竞争激烈,重试频繁发生,效率会受影响。
在JUC(java.util.concurrent )包下实现的很多类都用到了CAS操作

  • AbstractQueuedSynchronizer(AQS框架)
  • A AtomicXXX类

2.1 你知道CAS的执行流程吗:

一个当前内存值V、旧的预期值A、即将更新的值B,当且仅当旧的预期值A和内存值V相同时,将内存值修改为B并返回true,否则什么都不做,并返回false。如果CAS操作失败,通过自旋的方式等待并再次尝试,直到成功。
在这里插入图片描述

当线程A 已经把a的值修改为101 后,线程B 此时修改值为99 就会失败
在这里插入图片描述

此时重新获取a的值,然后在次进行比较和交换
在这里插入图片描述

2.2 你知道CAS的底层实现吗:

底层通过调用Unsafe 类中被native 修饰的方法进行实现;
在这里插入图片描述

2.3 你说下Synchronized 和CAS的区别

  • CAS 是基于乐观锁的思想:最乐观的估计,不怕别的线程来修改共享变量,就算改了也没关系,我吃亏点再重试呗。
  • synchronized 是基于悲观锁的思想:最悲观的估计,得防着其它线程来修改共享变量,我上了锁你们都别想改,我改完了解开锁,你们才有机会。

三、你知道JMM,你们项目中有使用过volatile吗

2.1 JMM Java 的内存模型

JMM(lava Memory Model)Java内存模型,定义了共享内存中多线程程序读写操作的行为规范,通过这些规则来规范对内存的读写操作从而保证指令的正确性。

在这里插入图片描述

你谈谈JMM

  • JMM(Java Memory Model)Java内存模型,定义了共享内存中多线程程序读写操作的行为规范,通过这些规则来规范对内存的读写操作从而保证指令的正确性
  • JMM把内存分为两块,一块是私有线程的工作区域(工作内存),一块是所有线程的共享区域(主内存)
  • 线程跟线程之间是相互隔离,线程跟线程交互需要通过主内存

2.2 你知道volatile 吗

使用volatile 关键字修饰的属性,可以打破内存屏障,使得一个线程对其进行修改后,保证其它线程的可见性。一旦一个共享变量(类的成员变量、类的静态成员变量)被volatie修饰之后,那么就具备了两层语义

  • ① 保证线程间的可见性
  • ② 禁止进行指令重排序

2.2.1 你知道JVM的JIT(即时编译器)

JIT 在将代码进行编译时,会对代码优化,从而导致代码执行的先后顺序发生改变,从而在特定条件下发生问题。此时就可以使用volatile 关键字。
在这里插入图片描述

2.2.2 volatile 保证线程的可见性

在这里插入图片描述

2.2.3 你知道volatile的实现原理吗

volatile禁止指令重排序,用 volatile 修饰共享变量会在读、写共享变量时加入不同的屏障,阴止其他读写操作越过屏障,从而达到阳止重排序的效果.

发生指令重排序
在这里插入图片描述
使用volatile 禁止指令的重排序
在这里插入图片描述
你们使用volatile都遵从哪些规则

  • 写变量让volatile修饰的变量的在代码最后位置
  • 读变量让volatile修饰的变量的在代码最开始位置

四、你知道AQS吗

4.1 什么是AQS

全称是 AbstractQueuedSynchronizer,即抽象队列同步器。它是构建锁或者其他同步组件的基础框架
AQS与Synchronized的区别

在这里插入图片描述

4.2 请你描述下AQS 的工作机制

  • AQS是多线程中的队列同步器。是一种锁机制,它是做为一个基础框架使用的像ReentrantLock、Semaphore都是基于AQS实现的
  • AQS内部维护了一个先进先出的双向队列,队列中存储的排队的线程在AQS内部还有一个属性state,这个state就相当于是一个资源,默认是0(无锁状态),如果队列中的有一个线程修改成功了state为1,则当前线程就相等于获取了资源
  • 在对state修改的时候使用的cas操作,保证多个线程修改的情况下原子性,如果CAS 修改成功,代表获取了锁,可以继续业务的执行,否则将当前线程放入到阻塞队列中,等待锁获取
  • 当持有锁的线程释放了锁,则从队列中唤醒头部元素进行锁的获取;

在这里插入图片描述

4.3 你都有过Lock 的哪些锁

我在项目中使用到了ReentrantLock 锁,来对资源并发修改情况下进行加锁,ReentrantLock 锁的使用和原理详解可以参考:JAVA并发编程–4.1理解ReentrantLock

4.3.1 你知道ReentrantLock 实现的原理吗

ReentrantLock主要利用CAS+AQS队列来实现。它支持公平锁和非公平锁,两者的实现类似构造方法接受一个可选的公平参数(默认非公平锁),当设置为true时,表示公平锁,否则为非公平锁。公平锁的效率往往没有非公平锁的效率高,在许多线程访问的情况下,公平锁表现出较低的吞吐量。

在这里插入图片描述

ReentrantLock 的工作过程
在这里插入图片描述

  • 线程来抢锁后使用cas的方式修改state状态,修改状态成功为1,则让exclusiveOwnerThread属性指向当前线程,获取锁成功
  • 假如修改状态失败,则会进入双向队列中等待,head指向双向队列头部,tail指向双向队列尾部
  • 当exclusiveOwnerThread为null的时候,则会唤醒在双向队列中等待的线程
  • 公平锁则体现在按照先后顺序获取锁,非公平体现在不在排队的线程也可以抢锁

4.3.2 synchronized和Lock有什么区别

语法层面:
synchronized 是关键字,源码在 jvm 中,用 c++ 语言实现Lock 是接口,源码由jdk 提供,用java 语言实现使用 synchronized 时,退出同步代码块锁会自动释放,而使用 Lock 时,需要手动调用 unlock 方法释放锁

功能层面
二者均属于悲观锁、都具备基本的互斥、同步、锁重入功能Lock 提供了许多 synchronized 不具备的功能,例如公平锁、可打断、可超时、多条件变量Lock有适合不同场景的实现,如 ReentrantLock,ReentrantReadWriteLock(读写锁)

性能层面
在没有竞争时,synchronized 做了很多优化,如偏向锁、轻量级锁,性能不赖在竞争激烈时,Lock 的实现通常会提供更好的性能

五、你遇到过死锁吗,你们是怎样排查的

5.1 你了解死锁产生的条件吗

当一个线程需要获取多把锁时,就有可能发生死锁。

  • 一个资源每次只能被一个线程使用
  • 一个线程在阻塞等待某个资源时,不释放已占有资源
  • 一个线程已经获得的资源,在未使用完之前,不能被强行剥夺
  • .若干线程形成头尾相接的循环等待资源关系
  • 这是造成死铁必须要达到的4个条件,如果要避免死锁,只需要不满足其中某一个条件即可。而其中前3个条件是作为锁要符合的条件,所以要避免死铁就需要打破第4个条件,不出现循环等待锁的关系。

5.2 出现死锁后你们是怎么排查的

涉及死锁的线程都会处于等待状态,虽然系统可能还未完全停止工作,但由于死锁线程占用了部分资源(如CPU时间片、内存等),系统的整体性能会受到影响,表现为响应速度变慢、吞吐量下降等,请求结构一直等待数据返回。

我们通常使用jdk 自带的一些工具来进行排查:

  • 通过 jps:输出JVM中运行的进程状态信息
  • 通过jstack:查看iava进程内线程的维栈信息
  • 通过jconsole 连接到java 的应用程序,进行死锁检查
  • 通过jvisualvm 连接到java 的应用程序,进行死锁检查

总结

本文对Java 中进程内经常使用的锁,以及原理面试题进行汇总。

标签:Synchronized,Java,1.1,AQS,CAS,死锁,线程,volatile
From: https://blog.csdn.net/l123lgx/article/details/140121004

相关文章

  • 【java深入学习第4章】精通 Java 微服务:Spring Boot 与 Spring Cloud 的核心技术与设
    在现代软件开发中,微服务架构因其灵活性和可扩展性而备受青睐。本文将探讨Java微服务架构中的关键技术和设计原则,并通过SpringBoot和SpringCloud提供代码示例,展示如何构建一个简单的微服务应用。关键技术和设计原则服务拆分:将单体应用拆分为多个独立的微服务,每个服务负责特定......
  • 【java深入学习第2章】Spring Boot 结合 Screw:高效生成数据库设计文档之道
    在开发过程中,数据库设计文档是非常重要的,它可以帮助开发者理解数据库结构,方便后续的维护和扩展。手动编写数据库设计文档不仅耗时,而且容易出错。幸运的是,可以使用SpringBoot和Screw来自动生成数据库设计文档。什么是Screw?Screw是一个开源的数据库文档生成工具,它可以根据数据库......
  • 【java深入学习第3章】通过 Spring AOP 完成参数的加解密
    在现代应用中,数据的安全性越来越受到重视。为了保护敏感数据,我们常常需要对数据进行加密和解密。在这篇博客中,我将展示如何使用SpringAOP(面向切面编程)来实现对方法参数的加解密。什么是SpringAOP?SpringAOP是Spring框架中的一个模块,它提供了面向切面编程的功能。AOP允许我们将......
  • Java进阶之路66问 | 对接口签名是怎么理解的?如何防止接口重放攻击?
    接口签名为什么需要接口签名?现在越来越多的公司以API的形式对外提供服务,这些API接口大多暴露在公网上,所以安全性就变的很重要了。最直接的风险如下:非法使用API服务。(收费接口非法调用)恶意攻击和破坏。(数据篡改、DOS)因此需要设计一些接口安全保护的方式来增强接口......
  • Java进阶之路66问 | 什么是幂等性?如何保证接口的冥等性?
    API设计中的幂等性什么是幂等性幂等性是指无论一个操作执行多少次,最终的结果都是一样的。也就是说,重复执行同一个操作不会改变系统的状态或产生不同的结果。想象你在一栋大楼里等电梯。你按下电梯按钮的5楼按钮键,电梯开始向5楼的位置移动。后面即使你再按几次5楼按钮键,......
  • Java优雅使用线程池连接SFTP进行文件上传下载 解决请求量大问题
    Java优雅使用线程池连接SFTP进行文件上传下载解决请求量大问题使用FTP连接池降低资源消耗,提高响应速率为什么要使用线程池连接SFTP呢?在Java中使用线程池来连接SFTP(SecureFileTransferProtocol)工具的原因主要与性能、资源管理和效率有关。以下是一些关键原因:资源管......
  • 花几千上万学习Java,真没必要!(四)
    1、关系运算符:packagetest.com;publicclassRelationalArithmetic{ /*关系运算符用于比较两个值之间的关系,关系运算符的结果是一个布尔值,即true或false。 Java提供了6种关系运算符: >:大于 <:小于 >=:大于等于 <=:小于等于 ==:等于 !=:不等于*/publicstaticvoi......
  • Java计算机毕业设计个人健康管理系统的设计与实现(开题报告+源码+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着生活节奏的加快和健康意识的增强,个人健康管理成为了现代社会的重要议题。传统医疗模式下,人们往往只在出现症状时才寻求医生的帮助,这种“被动医疗......
  • Java计算机毕业设计的高校疫情防控系统(开题报告+源码+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景在全球新冠疫情持续蔓延的背景下,高校作为人群密集、流动性大的场所,其疫情防控工作面临着前所未有的挑战。传统的疫情防控手段难以有效应对疫情传播的......
  • Java计算机毕业设计校园二手物品交易平台(开题+源码+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景:随着高等教育的普及与校园生活的日益丰富,学生群体对各类学习资料、生活用品及电子产品的需求日益增长。同时,由于更新换代迅速及经济因素的考量,大量二......