2k字带你彻底搞懂Java中的各种锁!

本文介绍了Java中锁的引入原因,主要是为了解决多线程环境下的原子性、可见性和有序性问题。锁的分类包括共享锁和排它锁,以及从性能角度的乐观锁、悲观锁,和从锁实现层面的偏向锁、轻量级锁、重量级锁。此外,文章还讨论了锁的特性,如重入锁和分布式锁在解决并发问题中的作用和优化策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


前言:为什么引入锁?锁用来干什么?

本篇针对Java中常见的各种锁进行了简单总结,方便更加容易的理解锁机制。

在引入锁这个概念之前,我们要明确一点,即为什么要引入锁,锁用来干什么?

首先,锁的引入是为了解决多线程安全问题,具体的安全问题又可细化为如下3个方面:

(1)原子性

(2)可见性

(3)有序性

举一个实际场景下的例子:
请添加图片描述

假设主内存中有一个int类型的i变量,初始值为0,同时开启2个线程Thread 1和Thread 2,两个线程同时执行i++操作,那么最终的结果是多少?

最终的结果不确定,而是一个范围i≤2,为什么会这样?

原因就在于i++操作并非一个原子操作,i++在Java里我们认为就是1个自增操作,但从底层的汇编语言层面上讲,i++却是一个包含3个指令非原子操作

(1)从内存中加载i的值(get)

(2)对i进行递增(modify)

(3)把i的值重新写回内存(set)

当结果i=1时,是因为线程1线程2并行执行,同时内存中加载到i=0,那么进行自增后i=1,再次重新写入到内存当中也就得到了i=1;如果想要得到i=2,就必须加锁,使得2个线程串行执行

下面我们依次从功能性能体现锁特性层面上分别介绍各种类型的锁:


锁的分类

1 功能层面 : 共享锁(读锁)、排它锁(写锁)

共享锁同一时刻允许多线程同时抢占到锁。

排它锁同一时刻仅允许一个线程访问到共享资源。

2 性能层面:乐观/悲观锁、偏向锁/轻量级锁/重量级锁

加锁使得多线程并行执行变为串行执行,而从效率上讲,并行肯定要优于串行,故而会带来性能问题,而在实际场景下,我们往往需要同时兼顾安全性和性能

同样举一个例子,比如我们商品的库存数量的变动,既要保证安全性,又要同时保证性能,应该如何去优化?

一般我们会从以下几个方面去优化:

(1)锁粒度优化。

缩小锁的范围,保证锁竞争范围在目标的需求范围内即可。


(2)无锁化编程(乐观锁)。

乐观锁没有加锁,它是通过数据的版本来控制多线程并发时数据修改安全性

也可以通过CAS锁(保证原子性和可见性)


(3)偏向锁/轻量级锁/重量级锁(减少锁竞争)

首先,性能体现在如下3个方面:

1.竞争同步状态时,涉及到上下文切换(用户态与内核态切换)

2.线程阻塞/唤醒

3.并行到串行的改变

那么该如何优化性能?

由于1和3方面不好去改变,对于1,当竞争同步状态时必然涉及上下文切换,这是内核层面上的我们很难去处理;对于3,并行到串行保证了线程安全性;因此我们只能通过2来去做优化:

请添加图片描述

如上图,假设线程2先拿到了锁,此时线程1会进入阻塞状态,需要等到线程2释放锁之后,唤醒线程1才能拿到锁;此时我们便可以引入自旋锁(也叫轻量级锁),不必让线程1进入阻塞,而是在阻塞前让线程1进入一个循环不断重试去竞争该锁

考虑另外一种状况,加了锁的代码本身不存在竞争,此时便引入偏向锁的概念: 当线程1进入锁时,如果当前不存在竞争,那么就会把该锁偏向于线程1,待线程1下次进入时,就不再需要再去竞争该锁


(4)锁消除/锁膨胀(编译器层面优化)

锁消除:代码本身不存在安全问题加了锁之后JVM去编译时发现该锁导致了无效竞争,那么就会把该锁消除掉.

锁膨胀控制的锁的粒度太小了,导致频繁加锁、释放,频繁去竞争,从而JVM会把锁的范围扩大.


(5)读写锁(读多写少的情况下)

读操作不会影响数据的准确性,因为它不会修改数据

假设有一个方法内大部分操作都是去查询,那么就不需要加锁,这就是一种优化。

针对读多写少的场景下,读和读不去竞争锁,而读和写、写和写去竞争锁,这也是一种优化。


(6)公平锁/非公平锁

默认情况下锁都是非公平的,非公平锁的性能更好,因为其减少了线程的阻塞和唤醒


(7)悲观锁

认为所有访问都是非安全的,所以必须要通过加锁来去访问

总结:
偏向锁不存在竞争
轻量级锁存在轻微竞争
重量级锁正常加锁时实现的方式

3 锁特性层面:重入锁、分布式锁

(1)重入锁(避免死锁的一种设计)

一个线程抢占到锁,在释放之前再次去竞争同一把锁时,无需阻塞等待,而是直接进入重试


(2)分布式锁(用于解决分布式架构下的力粒度问题)

Sychronized解决了Java并发里的线程维度上的安全问题,而分布式锁则是用于解决进程维度上的安全问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

丷江南南

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值