程序员必知必会:各种锁的概念

您所在的位置:网站首页 360程序锁是什么意思 程序员必知必会:各种锁的概念

程序员必知必会:各种锁的概念

2024-07-10 17:55| 来源: 网络整理| 查看: 265

文章目录 锁的概念共享锁,排他锁乐观锁,悲观锁公平锁,非公平锁可重入锁,不可重入锁偏向锁、轻量级锁、自旋锁、重量级锁分布锁

锁的概念

同步访问共享数据时,为了保证数据操作的原子性,需要使用锁进行访问控制。锁,本质上是一个访问权限的标记。

在程序的世界里,有各种形式的数据,它们以各种形式被访问和存储。CPU 寄存器组,一级、二级缓存,内存,磁盘,设备缓存,而从进程的角度来说,变量,栈,堆,数据库,还有各种各样的缓存。

存在数据的地方,就存在访问控制!

锁,可以有多种实现策略,只要满足标记修改的原子性,及标记本身的可见性。

共享锁,排他锁

共享锁用于不更改数据的、只读、查询等操作,如 SELECT 语句,读文件等。获取共享锁的事务只能读数据,不能修改数据。

排它锁用于数据的修改,比如 INSERT,UPDATE,或 DELETE,同一资源在同一时间只能有一个用户获得排它锁。

在这里插入图片描述

乐观锁,悲观锁

乐观锁是一种策略,是指在操作数据时,以乐观的态度开启每次事务,认为该次操作不会遭遇冲突,也就是在操作数据时,不加锁,在进行数据更新的提交时,再去判断是否有数据冲突。

比如在数据库操作时,先给数据表加一个版本字段,每次更新会将记录的版本号加1。事务开始时,先查询并保存记录的版本,在事务提交时,比较该记录版本与当前记录版本是否一致,如果一致,说明没有冲突,可以直接提交;如果版本不一致,说明发生了冲突。

数据库本身并不支持乐观锁,可以通过上层框架实现,比如 Hibernate。 Java 中的乐观锁基本都是通过 CAS (Compare and Set)操作实现的,CAS是一种更新的原子操作,比较当前值跟传入值是否一样,一样则更新,否则失败。

public final boolean compareAndSet(V expectedValue, V newValue) { return VALUE.compareAndSet(this, expectedValue, newValue); }

悲观锁与乐观锁的思路相反,每次操作都要先获取响应的锁。共享锁和排它锁是悲观锁范畴下的不同实现。

在数据库中,还可以根据数据的范围大小,分为行锁,表锁,数据库锁等。

公平锁,非公平锁

顾名思义,公平锁讲究的是先来后到,先进入等待队列的用户,会先获得锁。而非公平锁,如果一个线程对锁发起了请求,需要等待,但在尚未将其放入等待队列之前,锁可用了,这时该线程会获得锁。

非公平锁性能高于公平锁性能的原因:

在恢复一个被挂起的线程与该线程真正运行之间存在着严重的延迟。相当于人从被叫醒要完全醒过来需要时间。

假设线程A持有一个锁,并且线程B请求这个锁。由于锁被A持有,因此B将被挂起。当A释放锁时,B将被唤醒,因此B会再次尝试获取这个锁。与此同时,如果线程C也请求这个锁,那么C很可能会在B被完全唤醒之前获得、使用以及释放这个锁。这样就是一种双赢的局面:B获得锁的时刻并没有推迟,C更早的获得了锁,并且吞吐量也提高了。

可重入锁,不可重入锁

可重入就意味着,线程可以进入任何一个它已经拥有的锁所同步着的代码块。Java 中的 ReentrantLock 和 synchronized 都是可重入的锁。

不可重入锁的代码示例:

public class Lock{ private boolean isLocked = false; public synchronized void lock() throws InterruptedException{ while(isLocked){ wait(); } isLocked = true; } public synchronized void unlock(){ isLocked = false; notify(); } }

如果再同一个方法里,连续调用两次 lock() 方法,会发生死锁。

可重入锁的代码示例:

public class Lock{ boolean isLocked = false; Thread lockedBy = null; int lockedCount = 0; public synchronized void lock() throws InterruptedException{ Thread thread = Thread.currentThread(); while(isLocked && lockedBy != thread){ wait(); } isLocked = true; lockedCount++; lockedBy = thread; } public synchronized void unlock(){ if(Thread.currentThread() == this.lockedBy){ lockedCount--; if(lockedCount == 0){ isLocked = false; notify(); } } } } 偏向锁、轻量级锁、自旋锁、重量级锁

参考 https://www.cnblogs.com/lzh-blogs/p/7477157.html

分布锁

参考 https://www.cnblogs.com/seesun2012/p/9214653.html



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3