redis锁

作者: 7d972d5e05e8 | 来源:发表于2020-06-13 10:27 被阅读0次

1、单节点的redis锁
优点:快
缺点:不安全(redis节点断电,网络不通,锁过期等等)

2、多节点redis锁,即RedLock
参考文章:https://www.cnblogs.com/baichunyu/p/11631750.html

优点:快,相对安全(上了分布式redis,解决了单点问题)
缺点:还是不完全安全。

为啥说它相对安全呢?
可以参考这篇文章:https://www.cnblogs.com/baichunyu/p/11631777.html
英文博客:How to do distributed locking

总结下:应用client1自己由于gc导致STW的话,有可能因为时间过长,导致redLock的key过期,其他应用client2获取到锁,导致不安全。gc只是其中一个原因,还包括:网络包的延迟,cpu抢占,页中断等等可能造成pause的地方,都是不安全的。

二、synchronized锁

我根据图总结了下:
1、无竞争情况下,是偏向锁。不管是单线程,还是多线程交替执行,只要没有竞争发生。
2、轻量级锁:只要出现一次竞争,升级为轻量级。并且竞争不激烈(自旋次数内都能拿到锁),就一直在轻量级锁
3、只要有一个竞争线程在自旋次数达到拿不到锁,它就把锁升级为重量级锁。
锁只能膨胀,不能缩小。

原文地址:https://blog.csdn.net/wojiao228925661/article/details/100145157

啃碎并发(七):深入分析Synchronized原理

synchronized重量级锁是通过JVM的monitor来实现的,monitor是基于操作系统的mutex来实现。JVM的monitor用来实现可重入,等待队列,阻塞队列等等JVM层面的功能。monitor在JVM是c++实现,结构如下:

ObjectMonitor() {
    _header       = NULL;
    _count        = 0;
    _waiters      = 0,
    _recursions   = 0;
    _object       = NULL;
    _owner        = NULL;
    _WaitSet      = NULL;
    _WaitSetLock  = 0 ;
    _Responsible  = NULL ;
    _succ         = NULL ;
    _cxq          = NULL ;
    FreeNext      = NULL ;
    _EntryList    = NULL ;
    _SpinFreq     = 0 ;
    _SpinClock    = 0 ;
    OwnerIsThread = 0 ;

很明显里面的_owner用来实现重入功能,_WaitSet用来实现等待队列,_EntryList实现阻塞队列。

_owner:指向持有ObjectMonitor对象的线程
_WaitSet:存放处于wait状态的线程队列
_EntryList:存放处于等待锁block状态的线程队列
_recursions:锁的重入次数
_count:用来记录该线程获取锁的次数

多线程获取锁的时候,会先进入_EntryList排队,然后monitor会选择对头拿锁。然后其他线程继续在_EntryList阻塞着。等到获取线程锁执行wait(),暂时放弃锁的时候,该线程会自动进入_WaitSet等待被唤醒(没唤醒前是不参与竞争锁的),然后唤醒_EntryList其中一个线程。如果这个时候条件到达换行了_WaitSet里面的某个线程,那么它会加入到_EntryList和其他正在竞争锁的线程一起,重新竞争锁。

image.png

PS:序号4的线程,在被notify唤醒后,不应该直接进入The Owner。它应该进入阻塞队列,一同参与竞争锁。

四、CAS乐观锁,JVM是如何实现呢?

既然synchronized重量级锁是通过系统调用mutex lock来实现,它要发生用户态到内核态的切换,代价太高。那么CAS是怎么实现原子性的呢?它怎么就不需要用户态到内核态的切换?
cas不需要调用系统命令,所以无需用户态到内核态的切换。那为啥它不需要系统命令呢?因为现代cpu提供了cas原子性指令,帮助了JVM实现。那么提供了这个cas指令,就一定不需要系统调用吗?其实还有个关键特征,就是这个cpu提供的cas指令不是特权指令。如果它是特权指令,只能有操作系统来执行,那么就算有cas指令,JVM用它的话照样会发生用户态到内核态切换,代价照样高。所以,幸好cpu的cas指令不是特权指令,就像普通的load,push等等大多数指令一样,不是特权指令。

JDK提供CAS的api,具体实现是JVM的JNI来做的。JNI是c++的,它通过直接调用cpu指令来实现。如下:

UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSetInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x)) {
  oop p = JNIHandles::resolve(obj);
  jint* addr = (jint *)index_oop_from_field_offset_long(p, offset);
  // 调用Atomic.cpp中的cmpxchg()
  return (jint)(Atomic::cmpxchg(x, addr, e)) == e;
} UNSAFE_END

没有发生系统调用,就达到了原子性了吧!

相关文章

  • 秒杀随笔

    方法: mysql悲观锁 mysql乐观锁 PHP+redis分布式锁 PHP+redis乐观锁(redis wa...

  • 大佬浅谈分布式锁

    redis 实现 redis 分布锁一、redis 实现分布式锁(可重入锁)redission 实现分布式锁1、对...

  • Redis实现分布式锁

    Redis实现分布式锁 一、Redis单节点实现 (一) 获取锁 使用 Redis 客户端获取锁,向Redis发出...

  • 分布式锁之redis-lua脚本

    目录 redis分布式锁,Lua,Lua脚本,lua redis,redis lua 分布式锁,redis set...

  • redis锁

    1、单节点的redis锁优点:快缺点:不安全(redis节点断电,网络不通,锁过期等等) 2、多节点redis锁,...

  • Redis分布式锁

    Redis分布式锁 实现 Redis 锁主要利用 Redis 的 setnx 命令。 加锁命令:SETNX key...

  • 死磕 java同步系列之redis分布式锁进化史

    问题 (1)redis如何实现分布式锁? (2)redis分布式锁有哪些优点? (3)redis分布式锁有哪些缺点...

  • 使用JVM提高秒杀系统性能

    前提 使用redis分布式锁,解决秒杀系统库存为零 继续扣减问题 redis分布式锁出现的问题 使用redis锁,...

  • Zookeeper实现分布式锁(一)While版

    前面文章讲解了用Redis实现分布式锁的方式: 分布式锁之Redis实现(acquire)分布式锁之Redis实现...

  • 基于redis实现的分布式锁

    本文要点 基于redis实现分布式锁demo 基于redis实现分布式锁原理 基于redis实现分布式锁优缺点 正...

网友评论

      本文标题:redis锁

      本文链接:https://www.haomeiwen.com/subject/gwghwhtx.html