我们一起聊聊 Java 中的锁

开发 前端
java中synchronized 关键字修饰的锁为不可中断锁,一旦线程申请了锁,需要等获取锁之后执行完毕逻辑后,不可以被中断。

一、偏向锁,轻量级锁,重量级锁

这三种锁特指 synchronized 锁的状态,通过java对象的头mark world 来标识锁状态。

偏向锁 有时候我们加锁了,但是实际上却不存在竞争,所以没必要上锁,只要打个标识即可,这就是偏向锁的思想。如果一个对象初始化后,还没有任何线程来访问它,它就是可偏向的,第一个线程来访问它的时候,就把这个线程记录下来,如果下次仍然是这个线程访问,因为它是这个偏向锁的拥有者,所以直接获取锁,开销很小。

轻量级锁 如果synchronized 是被java的多个线程交替访问,不是同时竞争的,或者竞争的时间短,用CAS(Compare And Set)方式来轮询获取锁,不用经过上下文切换,这种时候没必要用重量级锁。

轻量级锁指原来是偏向锁,这时候一个非偏向锁拥有者的线程来访问对象,那么这个偏向锁就升级为轻量级锁,即通过轮询方式来获取锁,不用阻塞。

重量级锁 对于竞争比较激烈的场景,采用轻量级锁就需要等待很长时间的空转,这时候适合用重量级锁。它利用重量级锁的同步机制实现,开销比较大。

锁升级

总结: 偏向锁性能最好不用CAS操作,轻量级锁利用CAS和自旋避免重量级操作,性能次之;重量级锁利用系统实现,需要上下文切换,最终,性能最差。

二、可重入锁/非可重入锁

可重入锁即获取锁的线程,不释放锁的情况下,可以再次获取这个锁。非可重入锁即线程获取锁之后,只能释放了锁之后,才能再次获取锁。

ReentrantLock 即可重入锁。

三、共享锁、独占锁

共享锁是可以同时被多个线程同时占有的锁,独占锁即只能被一个线程所占有。我们常用的读写锁,读锁属于共享锁,可以同时被多个线程占有,写锁属于独占锁,只能被一个线程所占用。

四、公平锁、非公平锁

如果锁已经被占用,后续要获取锁的线程就会等待,开始排队,如果锁被释放后,等待时间最长的线程获取锁,这就是公平锁,非公平锁会在一定情况下准许插队的情况。

五、悲观锁和乐观锁

悲观锁即在获取资源之前,先获取锁,然后就进行操作,这样保证其他想操作的线程因为没有获取锁,所以无法操作。乐观锁,倾向于认为竞争不激烈,它不要求操作资源前先获取锁,而是直接用CAS操作,即更新的时候判断值是不是原来获取的值,如果是就直接修改(判断和更改是原子操作),如果不是就重试,在不独占的时候就完成了资源的修改。

六、自旋锁和非自旋锁

自旋锁的理念是如果线程拿不到锁,不会阻塞或释放 CPU 资源而是采用循环等待的方式,不断获取锁,这种方式即为自旋,我理解即为不停止循环判断锁是否释放了;非自旋锁,如果没有获取锁,则会进入阻塞或做其他事情。

七、可中断锁和不可中断锁

java中synchronized 关键字修饰的锁为不可中断锁,一旦线程申请了锁,需要等获取锁之后执行完毕逻辑后,不可以被中断。 ReentrantLock 即可中断锁,在获取锁的过程中,可以被中断,不用必须等待其他线程释放锁后,再获取锁。

责任编辑:武晓燕 来源: 今日头条
相关推荐

2022-07-29 08:17:46

Java对象内存

2023-10-26 08:38:43

SQL排名平分分区

2022-10-08 00:00:05

SQL机制结构

2023-04-26 07:30:00

promptUI非结构化

2023-08-04 08:20:56

DockerfileDocker工具

2023-08-10 08:28:46

网络编程通信

2023-06-30 08:18:51

敏捷开发模式

2022-05-24 08:21:16

数据安全API

2023-09-10 21:42:31

2024-02-20 21:34:16

循环GolangGo

2021-08-27 07:06:10

IOJava抽象

2023-11-10 08:04:43

Java 17Java 11JDK

2024-09-09 08:53:56

2024-06-14 09:32:12

2022-09-08 08:50:17

SSDOracleCPU

2023-08-02 08:35:54

文件操作数据源

2023-03-07 07:05:29

生产数据库运维

2021-07-31 11:40:55

Openresty开源

2022-02-23 08:41:58

NATIPv4IPv6

2024-07-26 09:47:28

点赞
收藏

51CTO技术栈公众号