全国服务热线:400-6263-721

位置:苏州达内IT培训学校 > 学校动态 > Java 中的锁

Java 中的锁

来源:苏州达内IT培训学校时间:2022/7/13 15:09:44

  为啥是 Java 中的锁呢, 因为 锁的种类 也有很多的,像我们平时使用的 MySQL,它也有自己的 表锁,行锁,间隙锁 ... ... 还有 基于redis 的分布式锁 (RedLock——红锁)呀,zookeeper的分布式锁 等各种各样的

  乐观锁

  说到这个就不得不提下 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 问题

  悲观锁

  这个就和乐观完全相反啦~ 不管读操作还是写操作,都悲观的认为会被别的线程改变,所以 不管是读还是写都会 加锁

  概念:

  悲观的认为,读写都要加锁,不然值会被其他线程改变~

  实现方式:

  synchronized ,ReentrantLock

  公平锁

  公平嘛,要讲究先来后到

  概念:

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

  原理:主要依赖于维护这个锁的 等待队列,当队列为空时就直接占有锁, 不为空就加入到 等待队列 的末尾,然后按照 FIFO 的原则去获取锁。

  实现方式:

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

  非公平锁

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

  概念:

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

  原理:非公平锁会尝试获取锁,失败的话会加入到 等待队列 的末尾,然后按照 FIFO 的原则去获取锁 ,变成公平锁的方式~

  实现方式:

  创建 ReentrantLock 时,显示指定 new ReentrantLock(false) 或者使用默认的方式 new ReentrantLock();

  还有 synchronized 这个关键字也是非公平的

  独享锁(独占锁)

  独自占有锁,不和其他线程共享~ 和 互斥锁,排他锁,悲观锁 同义

  概念:

  只允许一条线程占有该锁

  实现方式:

  synchronized ,ReentrantLock 还有 ReentrantReadWriteLock 中 的 写锁

  共享锁

  可以和其他线程共享该锁~ 和 乐观锁,读写锁 同义

  概念:

  锁可被多个线程所持有

  实现方式:

  ReentrantReadWriteLock ,ReadWriteLock 这两个中的 读锁

  互斥锁(同步锁)

  可以理解为独占锁的具体实现~

  概念:

  表示该资源只能被一条线程访问,不能被其他访问

  实现方式:

  synchronized ,ReentrantLock

  读写锁

  顾名思义~ 有读锁和写锁

  读读不互斥

  读写互斥

  写写互斥

  概念:

  表示该资源允许 多条持有读锁的线程共同访问,但是只允许一条持有写锁的线程独占

  实现方式:

  ReentrantReadWriteLock ,ReadWriteLock

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

  可重入锁(递归锁)

  什么是可重入呢~

  概念:

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

  特点:

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

  实现方式:

  synchronized ,ReentrantLock

  分段锁

  这个主要是 Jdk1.7 版本 的 CurrentHashMap

  概念:

  简单回忆下~

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

  实现方式:

  synchronized ,ReentrantLock

  自旋锁

  哈哈 看了上文之后是不是觉得这个也特眼熟呀~

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

  概念:

  让线程不断地循环,去尝试获取锁

  实现方式:

  CAS

  这里其实有很多可以扩展的,除了它的优缺点之外,还有 自适应自旋 这个和 虚拟机 相关的 ,埋个坑

  死锁

  情景模拟

  线程1 拥有 资源A 的锁,线程2 拥有 资源B 的锁,但是线程1在持有A锁的情况下,还想拥有B锁。同理 线程2在持有B锁的情况下,还想拥有A锁。他们两就这样僵持着,互相等待对方释放锁

  概念:

  死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。

  锁升级

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

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

领取试听课
每天限量名额,先到先得

尊重原创文章,转载请注明出处与链接:http://www.peixun360.com/1707/news/546018/违者必究! 以上就是苏州达内IT培训学校 小编为您整理 Java 中的锁的全部内容。

温馨提示:提交留言后老师会第一时间与您联系!热线电话:400-6263-721