Java锁常见面试题

图片引用自:不可不说的Java“锁”事 - 美团技术团队

1 java内存模型

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

2 锁的概念

2.1 什么是锁

在Java中的锁主要是用于保障线程在多并发的情况下数据的一致性。就是实现并发的原子性。

2.2 为什么加锁

在多线程编程中为了保证数据的一致性,我们通常需要在使用对象或者调用方法之前加锁,这时如果有其他线程也需要使用该对象或者调用该方法,则首先要获得锁,如果某个线程发现锁正在被其他线程使用,就会进入阻塞队列等待锁的释放,直到其他线程执行完成并释放锁,该线程才有机会再次获取锁并执行操作。这样做可以保障了在同一时刻只有一个线程持有该对象的锁并修改该对象,从而保障数据的安全性。

3 悲观锁 VS 乐观锁

悲观锁:悲观锁认为自己在使用数据的时候一定有别的线程来修改数据,因此在获取数据的时候会先加锁,确保数据不会被别的线程修改,阻塞直到拿到锁。

实现方式:Java中悲观锁是通过synchronized关键字或ReentrantLock接口来实现的。

应用场景:悲观锁适合写操作多的场景,先加锁可以保证写操作时数据正确。

乐观锁:认为在使用数据时不会有别的线程修改数据,所以不会添加锁,只是在更新数据的时候去判断之前有没有别的线程更新了这个数据。如果这个数据没有被更新,当前线程将自己修改的数据成功写入。如果数据已经被其他线程更新,则根据不同的实现方式执行不同的操作(例如报错或者自动重试)。

实现方式:乐观锁在Java中是通过使用无锁编程来实现,最常采用的是CAS算法,Java原子类中的递增操作就通过CAS自旋实现的。相对于对于 synchronized 这种阻塞算法,CAS是非阻塞算法的一种常见实现。所以J.U.C在性能上有了很大的提升。当然,如果并发非常严重,那么会导致CAS的自旋非常严重,此时性能反倒不如直接使用悲观锁。

应用场景:乐观锁适合读操作多的场景,不加锁的特点能够使其读操作的性能大幅提升,这样可以提高吞吐量。

// ------------------------- 悲观锁的调用方式 -------------------------
// synchronized
public synchronized void testMethod() {// 操作同步资源
}
// ReentrantLock
private ReentrantLock lock = new ReentrantLock(); // 需要保证多个线程使用的是同一个锁
public void modifyPublicResources() {lock.lock();// 操作同步资源lock.unlock();
}// ------------------------- 乐观锁的调用方式 -------------------------
private AtomicInteger atomicInteger = new AtomicInteger();  // 需要保证多个线程使用的是同一个AtomicInteger
atomicInteger.incrementAndGet(); //执行自增1

3.1 synchronized VS Lock


1、synchronized是Java关键字,在JVM层面实现加锁和解锁;Lock是一个接口,在代码层面实现加锁和解锁。

2、synchronized可以用在代码块上、方法上;Lock只能写在代码里。

3、synchronized在代码执行完或出现异常时自动释放锁;Lock不会自动释放锁,需要在finally中显示释放锁。

4、synchronized会导致线程拿不到锁一直等待;Lock可以设置获取锁失败的超时时间。

5、synchronized无法得知是否获取锁成功;Lock则可以通过tryLock得知加锁是否成功。

6、synchronized锁可重入、不可中断、非公平;Lock锁可重入、可中断、可公平/不公平,并可以细分读写锁以提高效率

7、都是悲观锁,都可以解决线程安全问题

3.2 CAS

CAS全称 Compare And Swap(比较与交换),是一种无锁算法。在不使用锁(没有线程被阻塞)的情况下实现多线程之间的变量同步。java.util.concurrent包中的原子类就是通过CAS来实现了乐观锁。

CAS算法涉及到三个操作数:

  • 需要读写的内存值 V。
  • 进行比较的值 A。
  • 要写入的新值 B。

4 volatile

参考另外一篇文章:java并发编程中的四个关键字:ThreadLocal、Volatile、Synchronized和Atomic-CSDN博客

5 线程安全

5.1 定义

当多个线程同时访问共享资源时,可能出现数据竞争、死锁等问题,导致程序运行出错或异常

5.2 常见问题

(1)数据竞争:当多个线程同时访问同一个资源时,会导致数据不一致,比如在多线程环境下,多条线程同时修改同一个变量,可能导致该变量值不可测。

(2)死锁:多线程间同时等待对方释放资源,导致程序无法继续运行,进入死锁状态。

(3)非原子操作:某些操作需要多条指令才能完成,如果多条线程同时执行这些操作,就会出现部分执行的情况,导致程序结果不正确。

(4)内存泄漏:由于程序设计不当,可能出现内存无法回收的情况,导致内存泄漏。

多个线程可以共享一个进程的变量时,如果线程需要对这个变量进行修改操作,则可能会因为数据更新不及时导致变量信息不准确而引发线程不安全。如果线程对这个变量只有读操作,没有更新操作则这个线程没有线程安全问题。

5.3 原因

多个线程同时访问同一个共享资源且存在修改该资源

5.4 解决方法--线程同步

为了解决线程安全问题就要引出线程同步这个概念。

如何保证线程安全:队列和锁 保证线程同步的安全性,让多个线程实现先后依次访问共享资源,这样就解决了安全问题。

加锁,把共享资源进行上锁,每次只能一个线程进入访问完毕以后解锁,然后其他线程才能进来。

1、同步代码块:Synchronized

2、同步方法:Synchronized

3、Lock锁:ReentrantLock类实现了Lock。比较常用的是ReentrantLock,可以显式加锁,释放锁

6 死锁

5.1 什么是死锁

不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁。

出现死锁后,不会出现异常,不会出现提示,只是所有的线程都处于阻塞状态,无法继续。

如果没有外部干预,线程会一直阻塞无法往下执行,这些一直处于相互等待资源的线程就称为死锁线程。

6.2 产生死锁的四个必要条件


1.资源互斥:对所分配的资源进行排它性控制,锁在同一时刻只能被一个线程使用。

2.不可剥夺:线程已获得的资源在未使用完之前,不能被剥夺,只能等待占有者自行释放锁。

3.请求等待:当线程因请求资源而阻塞时,对已获得的资源保持不放

4.循环等待:线程之间的相互等待

6.3 避免死锁

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

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

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

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

7 分布式锁

7.1 为什么

假设我们把代码部署到多台服务器上,还能生效吗?答案是否定的,这时分布式锁应运而生。

public synchronized void test1() {System.out.println("获取到锁1");
}
public void test2() {synchronized (Test.class) {System.out.println("获取到锁2");}
}

7.2 Redis分布式锁

图片来源于:Java分布式锁面试题_殷十娘的博客-CSDN博客

8 sleep() VS wait()


1、sleep方法没有释放锁,而wait方法释放了锁。

2、都可以暂停线程的执行。

3、wait()通常被用于线程交互/通信,sleep()通常被用于暂停执行。

4、wait()方法被调用后,线程不会自动苏醒,需要别的线程调用同一个对象上的notify()或者notifyAll方法,sleep方法执行完成后,线程会自动苏醒。或者可以使用wait(long timeout)超时后线程会自动苏醒。

9 单例模式

加入violate可以避免重排序

class SingletonClass {private static violate SingletonClass instance = null;public static SingletonClass getInstance() {if (instance == null) {synchronized(SingletonClass.class) {if (instance == null) {instance = new SingletonClass();}}}return instance;}
}

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

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

相关文章

c语言从入门到实战——函数递归

函数递归 前言1. 递归是什么?2. 递归的限制条件3. 递归举例3.1 举例1:求n的阶乘3.1.1 分析和代码实现3.1.2 画图推演 3.2 举例2:3.2.1 分析和代码实现3.2.2 画图推演 4. 递归与迭代 前言 函数递归是指一个函数直接或间接地调用自身&#xff…

使用javafx,结合讯飞ai,搞了个ai聊天系统

第一步:先在讯飞ai那边获取接入的api 点进去,然后出现这个页面: 没有的话,就点击免费试用,有了的话,就点击服务管理: 用v2.0的和用3的都行,不过我推荐用2.0版本 文档位置&#xff1…

【每日一题】数组中两个数的最大异或值

文章目录 Tag题目来源题目解读解题思路方法一:哈希集合 其他语言python3 写在最后 Tag 【哈希集合】【位运算-异或和】【数组】【2023-11-04】 题目来源 421. 数组中两个数的最大异或值 题目解读 找出数组中两个数的最大异或结果。 解题思路 一看数据量达到了 …

Flink日志采集-ELK可视化实现

一、各组件版本 组件版本Flink1.16.1kafka2.0.0Logstash6.5.4Elasticseach6.3.1Kibana6.3.1 针对按照⽇志⽂件⼤⼩滚动⽣成⽂件的⽅式,可能因为某个错误的问题,需要看好多个⽇志⽂件,还有Flink on Yarn模式提交Flink任务,在任务执…

vSLAM中IMU预积分的作用--以惯性导航的角度分析

作为一个学过一点惯导的工程师,在初次接触视觉slam方向时,最感兴趣的就是IMU预积分了。但为什么要用这个预积分,在看了很多材料和书后,还是感觉模模糊糊,云里雾里。 在接触了vSLAM的更多内容后,站在历史研究…

如何避免 JavaScript 中的内存泄漏?

一、什么是内存泄漏? JavaScript 就是所谓的垃圾回收语言之一,垃圾回收语言通过定期检查哪些先前分配的内存仍然可以从应用程序的其他部分“访问”来帮助开发人员管理内存。垃圾回收语言中泄漏的主要原因是不需要的引用。如果你的 JavaScript 应用程序经…

java中:cmd界面输入javac后提示:找不到或无法加载主类,怎么解决

找不到或无法加载主类 检查环境变量cmd下用 java命令运行文件,提示找不到主类待续、更新中 检查环境变量 CLASSPATH 少写.;安装jdk过程有两部,一步为安装jdk文件夹,全部一致; 另一步为安装jre文件夹与jdk文件夹不一致(或者文件夹安装位置, 一路全部默认)path中将java变量移到顶…

js调整table表格上下相邻元素顺序

有时候我们会遇到要通过箭头控制table表格上下顺序的需求,如下: 点击向下就将该元素下移一位,下面的一位元素就移上来,点击向上就将该元素上移一位,上面的一位元素就移下来,也就是相邻元素互换位置顺序: <el-table :data="targetTable" border style=&quo…

HTTP 协议请求头 If-Match、If-None-Match 和 ETag

概述 在 HTTP 协议中&#xff0c;请求头 If-Match、If-None-Match、If-Modified-Since、If-Unmodified-Since、If-Range 主要是为了解决浏览器缓存数据而定义的请求头标准&#xff0c;按照协议规范正确的判断和使用这几个请求头&#xff0c;可以更精准的处理浏览器缓存&#x…

Springboot3整合Mybatis-plus3.5.3报错

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a; 报错以及Bug ✨特色专栏&#xff1a; …

研发效能DevOps: Git安装

目录 一、理论 1.Git 2.Git 工具 二、实验 1.Git安装 2.配置Git 3. VS Code加载Git 一、理论 1.Git &#xff08;1&#xff09;简介 Git 是一个分布式版本控制及源代码管理工具;Git 可以为你的项目保存若干快照&#xff0c;以此来对整个项目进行版本管理。 Git 是一个…

ASTM F963-23美国玩具安全新标准发布

新标准发布 2023年10月13日&#xff0c;美国材料与试验协会&#xff08;ASTM&#xff09;发布了新版玩具安全标准ASTM F963-23。 主要更新内容 与ASTM F963-17相比&#xff0c;此次更新包括&#xff1a;单独描述了基材重金属元素的豁免情况&#xff0c;更新了邻苯二甲酸酯的管控…

Java与Redis的集成以及Redis中的项目应用

一、Java连接Redis Redis与MySQL都是数据库&#xff0c;java操作redis其实跟操作mysql的过程是一样的。 1.1 导入依赖 打开IDEA&#xff0c;进入Java项目&#xff0c;导入pom依赖&#xff0c;代码如下&#xff1a; <dependency><groupId>redis.clients</gro…

MySQL笔记--Ubuntu安装MySQL并基于C++测试API

目录 1--安装MySQL 2--MySQL连接 3--代码案例 1--安装MySQL # 安装MySQL-Server sudo apt install mysql-server# 设置系统启动时自动开启 sudo systemctl start mysql # sudo systemctl enable mysql# 检查MySQL运行状态 sudo systemctl status mysql# 进入MySQL终端 sudo…

视频剪辑技巧:批量合并视频,高效省时,添加背景音乐提升品质

随着社交媒体的兴起&#xff0c;视频制作越来越受到人们的关注。掌握一些视频剪辑技巧&#xff0c;可以让我们轻松地制作出令人惊艳的视频。本文将介绍一种高效、省时的视频剪辑技巧&#xff0c;帮助您批量合并视频、添加背景音乐&#xff0c;并提升视频品质。现在一起来看看云…

hadoop配置文件自检查(解决常见报错问题,超级详细!)

本篇文章主要的内容就是检查配置文件&#xff0c;还有一些常见的报错问题解决方法&#xff0c;希望能够帮助到大家。 一、以下是大家可能会遇到的常见问题&#xff1a; 1.是否遗漏了前置准备的相关操作配置&#xff1f; 2.是否遗的将文件夹(Hadoop安装文件夹&#xff0c;/dat…

社区牛奶智能售货机为你带来便利与实惠

社区牛奶智能售货机为你带来便利与实惠 低成本&#xff1a;社区牛奶智能货机的最大优势在于成本低廉&#xff0c;租金和人工开支都很少。大部分时间&#xff0c;货柜都是由无人操作来完成销售任务。 购买便利&#xff1a;社区居民只需通过手机扫码支付&#xff0c;支付后即可自…

2023年03月 Python(三级)真题解析#中国电子学会#全国青少年软件编程等级考试

Python等级考试&#xff08;1~6级&#xff09;全部真题・点这里 一、单选题&#xff08;共25题&#xff0c;每题2分&#xff0c;共50分&#xff09; 第1题 十进制数111转换成二进制数是&#xff1f;&#xff08; &#xff09; A: 111 B: 1111011 C: 101111 D: 1101111 答案…

flink的安装与使用(ubuntu)

组件版本 虚拟机&#xff1a;ubuntu-20.04.6-live-server-amd64.iso flink&#xff1a;flink-1.18.0-bin-scala_2.12.tgz jdk&#xff1a;jdk-8u291-linux-x64.tar flink 下载 1、官网&#xff1a;https://flink.apache.org/downloads/ 2、清华镜像&#xff1a;https://mirr…

【Linux进行时】磁盘文件结构

磁盘 上篇文章&#xff0c;我们提及文件是存放在磁盘当中&#xff0c;本篇文件我们来了解一下磁盘的结构&#xff01;&#xff01;&#xff01; 磁盘的概念&#xff1a; ❓什么是磁盘&#xff1f; &#x1f4a1;磁盘&#xff08;disk&#xff09;是指利用磁记录技术存储数据…