JAVA并发编程-一文看懂全部锁机制

本文涉及的产品
注册配置 MSE Nacos/ZooKeeper,118元/月
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
云原生网关 MSE Higress,422元/月
简介: 曾几何时,面试官问:java都有哪些锁?小白,一脸无辜:用过的有synchronized,其他不清楚。面试官:回去等通知!今天我们庖丁解牛说说,各种锁有什么区别、什么场景可以用,通俗直白的分析,让小白再也不怕面试官八股文拷打。

曾几何时,面试官问:java都有哪些锁?小白,一脸无辜:用过的有synchronized,其他不清楚。面试官:回去等通知!

    今天我们庖丁解牛说说,各种锁有什么区别、什么场景可以用,通俗直白的分析,让小白再也不怕面试官八股文拷打。

    之前的文章说过《JAVA并发编程synchronized全能王的原理》、以及《JAVA并发编程JUC包之CAS原理》,synchronized、CAS都是常见的锁。那么锁的类型是如何划分的呢?

一、按特性划分

1.1 悲观锁和乐观锁

按线程访问共享资源时,要不要锁住同步资源来定义。比如synchronized就是悲观锁,数据库的行锁、表锁都是悲观锁。

CAS就是乐观锁,数据库版本号机制也是乐观锁。

    悲观锁的应用场景:大量更新修改操作,使用悲观锁,可以保证数据强一致性。

    乐观锁的应用场景:读多写少的场景,提高吞吐量。

1.2 可重入锁和不可重入锁

一个线程,是否可以重复获取同一把锁。比如synchronized、ReentrantLock是可重入锁,可以重复加锁。可重入锁在加锁N次后,解锁就需要进行N次解锁。效率较低,但是好处是可以避免死锁,因为在方法内部递归,如果使用普通锁,可能会出现死锁。而可重入锁支持线程重复进入同一个代码块。

1.3 公平锁和非公平锁

多线程竞争同一个锁时,是否需要排队,以及是否可以插队。

    公平锁,就是多个线程按顺序申请锁。比如new ReentrantLock(true),就是公平锁。

    非公平锁,就是多个线程获取锁不是按申请顺序获得,可以插队。比如new ReentrantLock(false), synchronized。

非公平锁的缺点,就是可能导致线程饥饿现象,某个线程或多个线程由于优先级较低,长期被其他优先级较高的线程插队抢夺锁资源,导致无法获得CPU执行。

1.4 独享锁和共享锁

    独享锁、共享锁,也叫排它锁和非排它锁。

依据是:多个线程能否同时共享同一个锁。

   独享锁=排它锁,比如synchronized、ReentrantLock,ReentrantReadWriteLock的write写锁,都是独享锁。

   共享锁=非排它锁,比如ReentrantReadWriteLock的readLock读锁就是共享锁。

   也有人说,互斥锁,其实也是独享锁。有人说读写锁,对应的就是ReentrantReadWriteLock。

二、按上锁方式划分

2.1 隐式锁和显式锁

    按是否显式的执行加锁和解锁过程。比如synchronized,我们使用它后,不需要显式的解锁。而JUC包的ReentrantLock就需要显式的lock(),unlock().

三、其他类型锁

自旋锁,锁获取失败后, 线程不会阻塞,而是循环尝试获取锁直至成功。比如CAS、轻量级锁都是自旋锁。

分段锁,将锁的粒度划分更细,当一个线程对一段数据进行加锁访问时,其他段的数据可以被其他线程同时访问。比如concurrentHashMap,就是使用锁分段技术。

四、synchronized的锁状态

无锁、偏向锁、轻量级锁、重量级锁四种状态。其中JDK1.6新增了偏向锁和轻量级锁。这四种状态是随着多线程竞争,逐级升级的状态,不可逆不可降级。是JVM特定给synchronized提升效率而做的优化。

   偏向锁:就是只有一个线程访问共享资源时,不会加锁,只是记录当前持有锁资源线程的锁类型,然后该线程每次执行这部分共享资源,都只是判断是否持有锁,以及当前锁类型。

   轻量级锁:在偏向锁的基础上,如果当前有两个线程在交替竞争锁,这时候将锁状态膨胀为【轻量级锁】。同时竞争失败的线程,不阻塞,用CAS自旋循环等待获取锁。

   重量级锁:轻量级锁,自旋一定次数后,膨胀为重量级锁,竞争失败的线程直接进入阻塞状态,等持有锁的线程释放锁后再唤醒。

相关文章
|
12天前
|
安全 Java 调度
Java编程时多线程操作单核服务器可以不加锁吗?
Java编程时多线程操作单核服务器可以不加锁吗?
32 2
|
6天前
|
Java
深入理解Java中的异常处理机制
【9月更文挑战第34天】在Java的世界里,异常处理是代码健壮性的守护神。本文将带你探索Java异常处理的奥秘,从基础语法到高级技巧,我们一步步揭开异常处理的面纱。你将学会如何捕获、声明和处理异常,以及如何自定义异常类型。让我们开始这段旅程,让代码更加稳健和可靠吧!
|
3天前
|
Java
深入浅出Java异常处理机制
【9月更文挑战第37天】在Java编程的世界里,异常处理是一项基础而重要的技能。它就像是我们生活中的急救箱,遇到意外时能及时救治,避免程序崩溃。本文将通过生动的例子和易于理解的语言,带你了解Java中的异常处理机制,从基本的try-catch语句到自定义异常的创建,让你的程序更加健壮和可靠。准备好了吗?让我们一起走进Java异常处理的大门,探索它的奥秘吧!
|
9天前
|
Java 程序员 开发者
深入理解Java中的异常处理机制
【9月更文挑战第31天】在Java编程中,异常处理是维护程序健壮性的关键。本文将通过浅显易懂的语言和生动的例子,带你了解Java异常处理的基本概念、分类以及如何优雅地处理它们。从初学者到资深开发者,每个人都能从中获得新的洞见和技巧,让你的代码更加健壮和易于维护。
12 4
|
8天前
|
Java 编译器 开发者
Java中的异常处理机制:从基础到进阶
本文深入探讨Java编程语言中的异常处理机制,从基础知识出发,逐步解析异常的分类、捕获和处理方法。通过实际案例分析,展示如何在开发过程中有效利用异常处理提高代码的稳定性和可维护性。进一步探讨了自定义异常的创建和使用场景,以及在Java中进行异常处理的最佳实践。文章旨在为Java开发者提供一个全面而详细的异常处理指南,帮助开发者更好地理解和运用Java的异常处理机制。
|
12天前
|
Java 数据库连接
深入理解Java异常处理机制
【9月更文挑战第28天】在Java编程中,异常处理是确保程序健壮性的关键。本文通过浅显易懂的语言和生动的例子,带你一步步了解Java的异常处理机制。从try-catch-finally的基本用法,到自定义异常类,再到异常处理的最佳实践,我们将一起探索如何在代码中优雅地处理那些不期而遇的小插曲。
16 4
|
1天前
|
缓存 安全 Java
Singleton:在 Java 编程中编写和使用的 6 种方法
Singleton:在 Java 编程中编写和使用的 6 种方法
5 0
|
2天前
|
安全 Java 编译器
了解final关键字在Java并发编程领域的作用吗?
【10月更文挑战第8天】在Java并发编程中,`final`关键字具有重要作用,包括保证变量的可见性和不可变性,防止对象引用被意外修改,并帮助编译器优化读取操作及消除不必要的同步。通过确保变量不可变,`final`增强了多线程环境下的安全性与性能。
|
10天前
|
Java
JAVA并发编程系列(13)Future、FutureTask异步小王子
本文详细解析了Future及其相关类FutureTask的工作原理与应用场景。首先介绍了Future的基本概念和接口方法,强调其异步计算特性。接着通过FutureTask实现了一个模拟外卖订单处理的示例,展示了如何并发查询外卖信息并汇总结果。最后深入分析了FutureTask的源码,包括其内部状态转换机制及关键方法的实现原理。通过本文,读者可以全面理解Future在并发编程中的作用及其实现细节。
|
4天前
|
Java 数据库 UED
Java的多线程有什么用
Java的多线程技术广泛应用于提升程序性能和用户体验,具体包括:提高性能,通过并行执行充分利用多核CPU;保持响应性,使用户界面在执行耗时操作时仍流畅交互;资源共享,多个线程共享同一内存空间以协同工作;并发处理,高效管理多个客户端请求;定时任务,利用`ScheduledExecutorService`实现周期性操作;任务分解,将大任务拆分以加速计算。多线程尤其适用于高并发和并行处理场景。