乐趣区

关于java:Java中的锁居然有这么多

小伙伴们早晨好呀~

干货可能会早退,然而不能缺席呀!😄

嘿嘿 这篇来讲讲锁 🔒 啦~

看完上文的 ConcurrentHashMap 是不是发现有很多个 锁呀,这篇就带大家缕一缕~ 😝


Java 中的锁

为啥是 Java 中的锁呢,因为 锁的品种 也有很多的,像咱们平时应用的 MySQL,它也有本人的 表锁,行锁,间隙锁 … … 还有 基于 redis 的分布式锁RedLock——红锁)呀,zookeeper 的分布式锁 等各种各样的🔒~

埋个坑🕳 ~ 当前写数据库专题的时候写写 😝

4ye 总结了一份思维导图,小伙伴们能够看看~

乐观锁

说到这个就不得不提下 JAVA 中的 CAS 了,它是这种思维的具体实现~,还记得上文 频繁呈现的 Unsafe 类吗,ConcurrentHashMap 就是通过它去调用这个 CAS(Compare And Swap / Set),去设置值的 😋

概念:

读不加锁,更新数据期间会加锁(保障原子性)

详解:

读数据时 会很乐观的认为别的线程没有在批改数据,所以不会上锁。

写数据时 会判断以后值和期望值一不一样,一样的话会进行批改,此时批改会加锁。

(这里还有些很硬核的点,波及到硬件层面的锁~ 基于 MESI 协定滴 前面具体专题再扩大下!😝)

实现形式:

CAS 机制、版本号机制,工夫戳机制

为什么会多前面两种机制呢,其实这里是为了解决这个 ABA 问题

ABA 问题

场景模仿,当初有三条线程

线程 1 读取变量 a,此时 a =1

线程 2 读取变量 a,此时 a =1, 比拟后将它改为 a=2

线程 3 读取变量 a,此时 a =2, 比拟后将它改为 a=1

这时线程 1 发现变量 a 还是 1,和原来一样,就将它改成其余值了

能够发现这个过程中 线程 1 在批改值的时候,线程 2,3 曾经批改过变量 a 的值了,然而它毫不知情~

所以呢,为了解决这个问题,就引入了这个 版本号机制 或者 工夫戳机制~

其实就是多比拟一个值,比方 每次更改时再比拟下这个版本号或者工夫戳对不对得上~

额 这里既然只讲 Java,那也不扯远啦~ 嘿嘿,不过情理还是通用的!

小伙伴们能够参考下 这个 原子类中的 AtomicStampedReference,它就解决了这个 ABA 问题

乐观锁

这个就和乐观齐全相同啦~ 不论读操作还是写操作,都乐观的认为会被别的线程扭转,所以 不论是读还是写都会 加锁

概念:

乐观的认为,读写都要加锁,不然值会被其余线程扭转~

实现形式:

synchronizedReentrantLock

偏心锁

偏心嘛,要考究先来后到 😄

概念:

多个线程依照申请锁的程序来获取锁

原理 :次要依赖于保护这个锁的 期待队列 ,当队列为空时就间接占有锁, 不为空就退出到 期待队列 的开端,而后依照 FIFO 的准则去获取锁。

实现形式:

创立 ReentrantLock 时,显示指定 new ReentrantLock(true)

其实是靠这个 AQS 来实现偏心和非偏心的,这里也埋个坑🕳 前面会详解这个专题的😋

非偏心锁

这个就不和你讲先来后到了 😄

概念:

多个线程 不依照先到先得的形式去获取锁,有可能后申请的线程会先失去锁~

原理 :非偏心锁会尝试获取锁,失败的话会退出到 期待队列 的开端,而后依照 FIFO 的准则去获取锁,变成偏心锁的形式~

实现形式:

创立 ReentrantLock 时,显示指定 new ReentrantLock(false) 或者应用默认的形式 new ReentrantLock();

还有 synchronized 这个关键字也是非偏心的

独享锁(独占锁)

单独占有锁,不和其余线程共享~ 😄 和 互斥锁,排他锁,乐观锁 同义

概念:

只容许一条线程占有该锁

实现形式:

synchronizedReentrantLock 还有 ReentrantReadWriteLock 中 的 写锁

共享锁

能够和其余线程共享该锁~ 😄 和 乐观锁,读写锁 同义

概念:

锁可被多个线程所持有

实现形式:

ReentrantReadWriteLockReadWriteLock 这两个中的 读锁

互斥锁(同步锁)

能够了解为独占锁的具体实现~😄

概念:

示意该资源只能被一条线程拜访,不能被其余拜访

实现形式:

synchronizedReentrantLock

读写锁

顾名思义~ 有读锁和写锁 😄

  • 读读不互斥
  • 读写互斥
  • 写写互斥

概念:

示意该资源容许 多条持有读锁的线程独特拜访,然而只容许一条持有写锁的线程独占

实现形式:

ReentrantReadWriteLockReadWriteLock

这里还波及到 锁的降级 ,还有 可重入 等一些有意思的点~,埋个坑🕳 前面也会写到的😋

可重入锁(递归锁)

什么是可重入呢~ 😄

概念:

当一个线程持有某个锁时,能够再次获取该锁而不会导致死锁或者阻塞

特点:

获取 n 次 锁,也要开释 n 次锁

实现形式:

synchronizedReentrantLock

分段锁

这个次要是 Jdk1.7 版本 的 CurrentHashMap 😄

概念:

简略回顾下~

CurrentHashMap 中 的 Segment 数组,put 操作时会调用 ReentrantLock 的 lock 办法,锁住该 Segment

实现形式:

synchronizedReentrantLock

自旋锁

哈哈 看了上文之后是不是感觉这个也特眼生呀~ 😄

小伙伴们能够参看下 CurrentHashMap 中源码对这块的实现,如 put 源码

概念:

让线程一直地循环,去尝试获取锁

实现形式:

CAS

这里其实有很多能够扩大的,除了它的优缺点之外,还有 自适应自旋 这个和 虚拟机 相干的,埋个坑🕳 😋

死锁

情景模仿

线程 1 领有 资源 A 的锁,线程 2 领有 资源 B 的锁,然而线程 1 在持有 A 锁的状况下,还想领有 B 锁。同理 线程 2 在持有 B 锁的状况下,还想领有 A 锁。他们两就这样僵持着,相互期待对方开释锁🔒

概念:

死锁是指两个或两个以上的过程在执行过程中,因为竞争资源或者因为彼此通信而造成的一种阻塞的景象,若无外力作用,它们都将无奈推动上来。此时称零碎处于死锁状态或零碎产生了死锁,这些永远在相互期待的过程称为死锁过程。

锁降级

无锁 -> 偏差锁 -> 轻量级锁 -> 重量级锁

这里波及到 锁优化技术 ,前面和 锁粗化 锁解除 等作为一个专题写写✍

👉 做了思维导图后发现这里有这么多专题得缕一缕的 o((>ω<))o

参考:《2020 最新 Java 根底精讲视频教程和学习路线!》
链接:https://juejin.cn/post/694313…

退出移动版