您真的了解Java中的锁吗?这7种不同维度下的锁知道吗?
写在开头
在上几篇博文中,我们聊到过volatile关键字,用它修饰变量可以保证可见性与有序性,但它并不是锁,在使用时并不会阻塞线程,且不保证原子性,属于一种轻量级、高效的同步方式,因此,如果我们的使用场景仅需要保持可见性或者有序性,那可选择volatile,但如果必须保证原子性的话,volatile就不行了。
在Java多线程中,想真正的保证线程的安全,离不开一个东西,那就是 锁 !我们今天就一起来学习一下Java中的锁,以及常见锁的分类。
认识锁
很多面试官在问到Java锁的时候,往往都会这样开头
同学,你真的了解Java中的锁吗?
在Java中锁是一种非常重要的同步机制,经过前面的学习我们了解到,在并发编程中,经常会遇到多个线程访问同一个共享资源,当多个线程同时对共享资源操作写时,会导致数据不一致。通过锁的同步机制,可以确保在某一时刻只有一个线程能够访问特定的代码块或对象。
Java中实现锁的历程
早在jdk1.5之前就已经引入了synchronized 关键字,这个单词翻译成中文即为“同步”之意, Java 早期版本中,synchronized 属于 重量级锁,效率低下;不过,在 Java 6 之后, synchronized 引入了大量的优化如自旋锁、适应性自旋锁、锁消除、锁粗化、偏向锁、轻量级锁等技术来减少锁操作的开销,这些优化让 synchronized 锁的效率提升了很多。JDK 1.5 开始,引入了并发工具包 java.util.concurrent.locks.Lock,让锁的功能更加丰富。
常用的锁
- synchronized 关键字锁定代码库
- 可重入锁 java.util.concurrent.lock.ReentrantLock
- 重复读写锁 java.util.concurrent.lock.ReentrantReadWriteLock
主流锁的分类
现在锁的分类根据不同维度大致分有7类,话不多说,先上一个思维导图便于记忆!

悲观锁 / 乐观锁
悲观锁:一律会对代码块进行加锁,如 synchronized、java.util.concurrent.locks.ReentrantLock;
乐观锁:默认不会进行并发修改,通常采用 CAS 算法不断尝试更新;
适应场景:悲观锁适合写操作较多的场景,乐观锁适合读操作较多的场景
自旋锁
自旋锁是指尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁,这样的好处是减少线程上下文切换的消耗,缺点是循环占有、浪费 CPU 资源。
偏向锁 / 轻量级锁 / 重量级锁
JDK 1.5 之后新增锁的升级机制,提升性能。通过 synchronized 加锁后,一段同步代码一直被同一个线程所访问,那么该线程获取的就是偏向锁;偏向锁被一个其他线程访问时,Java 对象的偏向锁就会升级为轻量级锁;再有其他线程会以自旋的形式尝试获取锁,不会阻塞,自旋一定次数仍然未获取到锁,就会膨胀为重量级锁
公平锁 / 非公平锁
公平锁:多个线程按照申请顺序来获取锁。如java.util.concurrent.lock.ReentrantLock.FairSync;
非公平锁:指多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程先获得锁。如 synchronized、java.util.concurrent.lock.ReentrantLock.NonfairSync。
可重入锁
指在同一个线程在外层方法获取锁的时候,进入内层方法会自动获取锁。JDK 中基本都是可重入锁,避免死锁的发生。
独享锁 / 共享锁
独享锁指锁一次只能被一个线程所持有。synchronized、java.util.concurrent.locks.ReentrantLock 都是独享锁;
共享锁:指锁可被多个线程所持有。ReadWriteLock 返回的 ReadLock 就是共享锁。
除了以上这6种锁之外,还有的面试题中提到了粗粒度锁与细粒度锁
粗粒度锁 / 细粒度锁
粗粒度锁:就是把执行的代码块都锁定;
细粒度锁:就是锁住尽可能小的代码块,java.util.concurrent.ConcurrentHashMap 中的分段锁就是一种细粒度锁;
粗粒度锁和细粒度锁是相对的,没有什么标准。
总结
OK,今天关于锁的介绍就写到这里啦,本文先做一个总体上的概括,在后续的更新中会做详细介绍呀!
结尾彩蛋
如果本篇博客对您有一定的帮助,大家记得留言+点赞+收藏呀。原创不易,转载请联系Build哥!

如果您想与Build哥的关系更近一步,还可以关注“JavaBuild888”,在这里除了看到《Java成长计划》系列博文,还有提升工作效率的小笔记、读书心得、大厂面经、人生感悟等等,欢迎您的加入!

您真的了解Java中的锁吗?这7种不同维度下的锁知道吗?的更多相关文章
- Java中获取键盘输入值的三种方法
Java中获取键盘输入值的三种方法 Java程序开发过程中,需要从键盘获取输入值是常有的事,但Java它偏偏就没有像c语言给我们提供的scanf(),C++给我们提供的cin()获取键盘输入值 ...
- Java中从控制台输入数据的几种常用方法
Java中从控制台输入数据的几种常用方法 一.使用标准输入串System.in //System.in.read()一次只读入一个字节数据,而我们通常要取得一个字符串或一组数字 //System.in ...
- Java中的ReentrantLock和synchronized两种锁定机制的对比
问题:多个访问线程将需要写入到文件中的数据先保存到一个队列里面,然后由专门的 写出线程负责从队列中取出数据并写入到文件中. http://blog.csdn.net/top_code/article/ ...
- Java中Elasticsearch 实现分页方式(三种方式)
目录 ES 简介 ES 的特点: 一.from + size 浅分页 二.scroll 深分页 scroll删除 三.search_after 深分页 ES 简介 Elasticsearch 是一个基 ...
- Java中的ReentrantLock和synchronized两种锁机制的对比
原文:http://www.ibm.com/developerworks/cn/java/j-jtp10264/index.html 多线程和并发性并不是什么新内容,但是 Java 语言设计中的创新之 ...
- 你真的了解JAVA中与Webservice相关的规范和实现吗?
非常多人在项目中使用Webservice,仅仅是知道怎样公布Webservice,怎样调用Webservice,但真要论其来龙去脉,还真不一定清楚. 一切一切还要从我们伟大的sun公司规范说起. JA ...
- Java内存管理-你真的理解Java中的数据类型吗(十)
勿在流沙筑高台,出来混迟早要还的. 做一个积极的人 编码.改bug.提升自己 我有一个乐园,面向编程,春暖花开! 作为Java程序员,Java 的数据类型这个是一定要知道的! 但是不管是那种数据类型最 ...
- 你真的知道Java中boolean类型占用多少个字节吗?
为什么要问这个问题,首先在Java中定义的八种基本数据类型中,除了其它七种类型都有明确的内存占用字节数外,就boolean类型没有给出具体的占用字节数,因为对虚拟机来说根本就不存在 boolean 这 ...
- 你真的理解Java中的try/catch/finally吗?
看几个例子,回顾一下执行顺序 例子1 无异常,finally中的return会导致提前返回 public static String test() { try { System.o ...
- 你真的了解JAVA中对象和类、this、super和static关键字吗
作者:小牛呼噜噜 | https://xiaoniuhululu.com 计算机内功.JAVA底层.面试相关资料等更多精彩文章在公众号「小牛呼噜噜 」 目录 Java对象究竟是什么? 创建对象的过程 ...
随机推荐
- 移位寄存器的设计(VHDL)及testbench的编写
移位寄存器是一种常用的存储元件,此处由D触发器构成,如下图所示. 当时钟边沿到来时,存储在移位寄存器的数据朝一个方向移动一个BIT位. 移位寄存器的功能主要为:串并转换,并串转换和同步延迟. vhdl ...
- JS Leetcode 852. 山脉数组的峰顶索引图解分析,高高的山峰一起吹山风吧。
壹 ❀ 引 本题来自LeetCode 852. 山脉数组的峰顶索引,难度依旧是简单,也是一道考二分法的题目,题目描述如下: 符合下列属性的数组 arr 称为 山脉数组 : arr.length > ...
- NC50615 取石子游戏 2
题目链接 题目 题目描述 有一种有趣的游戏,玩法如下: 玩家:2人: 道具:N堆石子,每堆石子的数量分别为 \(X_1,X_2,...,X_n\) : 规则: 游戏双方轮流取石子: 每人每次 ...
- Codeforces Round #821 (Div. 2) A-E
比赛链接 A 题解 知识点:贪心. 下标模 \(k\) 相同分为一组,共有 \(k\) 组,组间不能互换,组内任意互换. 题目要求连续 \(k\) 个数字,一定能包括所有的 \(k\) 组,现在只要在 ...
- Oracle system identifier already exists specify another SID
问题说明 Centos7重装Oracle,使用DBCA重新创建实例test的时候报错,中文意思是: Oracle系统标识符(SID)"test"已存在,请指定另一个SID. 问题原 ...
- Vue+SpringBoot+ElementUI实战学生管理系统-8.班级管理模块
1.章节介绍 前一篇介绍了专业管理模块,这一篇编写班级管理模块,需要的朋友可以拿去自己定制.:) 2.获取源码 源码是捐赠方式获取,详细请QQ联系我 :)! 3.实现效果 班级列表 修改班级 4.模块 ...
- win32 - 监控DNS是否发生改变
两种方法: 第一种是使用WMI进行后台轮询 第二种是查询注册表对应的DNS键值 Here: HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameter ...
- 07-Redis系列之-双写一致性,缓存详解和优化点
双写一致性 双写一致性指的是当我们更新了数据库的数据之后redis中的数据也要同步去更新. redis和mysql数据同步方案 先更新缓存,再更新数据库(然并软...) 先更新数据库,再更新缓存(一般 ...
- 【LeetCode递归】括号生成,使用dfs
括号匹配 数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合. 示例 1: 输入:n = 3 输出:["((()))","(() ...
- macOS Monterey 与以下电脑兼容下载操作流程解析
有时在开发iOS应用时我们时常遇到各种情况,比如手机升级了Xcode不支持这时候需要安装xcode但是xcode需要依奈相应系统本人小编整理了这种情况无法解决问题. 首相打开苹果标志进入到下面界面 进 ...