各种锁的概念
Posted qwertilh
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了各种锁的概念相关的知识,希望对你有一定的参考价值。
0、前言
JAVA 亦或是 OS 中会出现非常之多不同的锁,这些锁大多都按特性、功能、设计、属性等作为依据来进行分类,而不是具体到某一种代码实现
1、公平锁 vs 非公平锁
概念:在并发环境中,线程在获得锁的顺序/优先级是根据申请的时间顺序来安排的(FIFO),这样保证了所有的线程都有机会得到锁,不会产生操作系统概念中 “饥饿” 情况的产生,这样的锁机制称为公平锁。相反,如果在获得锁的过程中,先申请锁的线程有可能被后申请的锁抢占的情况则为非公平锁。
JAVA例子:JAVA 中 ReentrantLock 就可以分别实现公平和非公平两种方式。源码解析
2、可重入锁(递归锁) vs 不可重入锁(自旋锁)
概念:可重入锁指的是线程获得了某种锁(不妨称为 A 锁)且在其执行的过程中需要重复获得 A 锁,那么这个线程可依旧进入被 A 锁锁住的代码段。而不可重入锁则正好相反,一个线程不能够多次重复地进入一种锁。(如果你了解递归,那么可重入锁被也称递归锁从概念上看是十分好理解的)
代码示例:
下面的例子中,执行 methodA 需要获得两次 A 锁,如果 A 锁是可重入锁那么 methodB 就可以得以执行,否则(即A锁是不可重入锁)那么执行到 methodB 段就会被阻塞,需要 A锁 被执行 unlock 操作之后才能继续执行下去
public class Demo { private Lock lockA; public Demo(Lock Lock) { this.lockA = lock; } public void methodA() { lockA.lock(); methodB(); // 进入 B 后需要重复获得 lockA 锁 lockA.unlock(); } public void methodB() { lockA.lock(); //dosm lockA.unlock(); } }
使用 JAVA 代码实现简单的自旋锁(CAS)
public class SpinLock { private AtomicReference<Thread> sign =new AtomicReference<>(); public void lock(){ Thread current = Thread.currentThread(); while(!sign .compareAndSet(null, current)){ } } public void unlock (){ Thread current = Thread.currentThread(); sign .compareAndSet(current, null); } }
CAS方式实现的乐观自旋锁能够让线程一直处于活跃状态,不会被挂起,减少了上下文切换,提高效率。
JAVA例子:JAVA 中 ReentrantLock 和 Synchronized 都是可重入锁
3、悲观锁 vs 乐观锁
概念:
悲观锁 => 有一个“悲观”的心态,既每次取数据的时候,都会认为该数据会被修改,所以必须加一把锁才安心。
乐观锁 => 乐观的孩子,认为同一个数据不会发生并发操作的行为,所以取的时候不会加锁,只有在更新的时候,会通过例如版本号之类的来判断是否数据被修改了。
JAVA例子:JAVA中的乐观锁基本是用 CAS 思想实现,例如 AtomicInteger
4、共享锁 vs 排他锁 (数据库事务)
概念:
共享锁 => 也称读锁或S锁。如果事务对数据A加上共享锁后,则其他事务只能对A再加共享锁,不能加排它锁。获准共享锁的事务只能读数据,不能修改数据。
排它锁 => 也称独占锁、写锁或X锁。如果事务对数据A加上排它锁后,则其他事务不能再对A加任何类型的锁。获得排它锁的事务即能读数据又能修改数据。
JAVA例子:ReetrantReadWriteLock()
5、分布式锁
概念:我们上面聊的这些锁,都是在单个程序上面的不同线程之间来实现的,那么当我们的不同程序需要去竞争同一块资源的时候,这就需要分布式锁了,我们可以通过redis、zookeeper等中间件来实现分布式锁。
6、偏向锁、轻量级锁、重量级锁
//TODO
---------------------------------------------
---------------------------------------------
以上是关于各种锁的概念的主要内容,如果未能解决你的问题,请参考以下文章