java.util.concurrent.locks 包中的接口和实现类

Posted XeonYu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java.util.concurrent.locks 包中的接口和实现类相关的知识,希望对你有一定的参考价值。

上一篇

JUC以及并发,线程同步,线程安全的概念加深

上一篇博客中,我们使用了一个线程安全的Vector来解决多线程下向集合添加数据造成的数据安全问题,本质上还是用的synchronized关键字来实现的线程同步。

但是synchronized有以下缺陷:

  • synchronized 不支持公平性,锁一旦释放,任何线程都能去获得释放的锁,很有可能出现其中一个线程一直获取锁资源,其他线程一直获取不到锁资源。
  • 如果一个线程不能获取到 synchronized的锁,那该线程就会一直处于阻塞状态,直到获取锁,且不能中断,这样用起来比较死板

等等

而JUC中给我们提供的锁则可以解决上面的问题,而且使用起来更加灵活。

这里先来说一下synchronizedLock区别

  • synchronized 是Java关键字,Lock是java类
  • synchronized 是自动的,会自动释放锁。Lock是手动的,需要手动上锁,手动释放锁。
  • synchronized 无法判断获取锁的状态。Lock可以判断是否获取到锁
  • synchronized 如果一个线程获取到锁,其他线程只能一直等待。Lock可以不用一直等待下去,不会造成死锁,使用起来更加灵活。
  • synchronized 是可重入的非公平锁,不可以中断。Lock也是可重入锁,但是可以设置是否是公平锁,且可以被中断。

JUC Locks

JUC中的锁都在locks包中,我们先来看看在 java.util.concurrent.locks 包中都有哪些东西。

在这里插入图片描述

可以看到有三个接口分别是

  • Lock
  • ReadWriteLock
  • Condition

以及一些实现类,我们重点关注以下实现类即可:

  • ReentrantLock
  • ReentrantReadWriteLock
  • StampedLock

Lock 接口

看看Lock接口定义了哪些方法
在这里插入图片描述

  • lock() :如果锁可用,则获取锁,如果锁不可用,线程会被阻塞,直到获取到锁。该方法的特点是即使在获取到锁之前调用中断方法,也不会立即响应中断,而是优先继续走获取锁执行任务的逻辑。然后再抛出异常
  • lockInterruptably() :类似与lock(),但是该方法优先响应中断,如果在获取锁之前调interrupt,则立刻抛出InterruptedException异常,不再继续走后面的逻辑
  • tryLock() : 可以看做是非阻塞版本的lock(), 尝试立即获取锁,如果获取锁成功则返回true,否则返回false
  • tryLock(long time, TimeUnit unit) :跟tryLock类似,tryLock是立即返回值,这个方法是在指定时间段内获取到锁时返回true,否则返回false,多了个超时时间
  • unlock() :这个没啥好说的,就是释放锁
  • newCondition() :返回一个Condition实例,该实例就是用来实现类似于Object中的wait和notify功能的

再来看看哪些类实现了Lock接口
在这里插入图片描述
如上所示,ReentrantLock和一些其他锁的内部类都实现了lock这个接口。


ReadWriteLock 接口

先看看ReadWriteLock 的源码
在这里插入图片描述

可以看到,就定义了两个方法,且返回值类型是上面的Lock类型

  • readLock() :用来读的锁
  • writeLock :用来写的锁

再来看看实现这个接口的类
在这里插入图片描述

可以看到,有ReentrantReadWriteLockStampedLock

ReadWriteLock 维护了一对锁,分别是读锁和写锁,读锁用于只读操作,写锁用于操作。

那么问题来了,为啥有了Lock接口,还要在弄个ReadWriteLock呢?

因为,我们所说的数据安全问题,都是在写操作(修改数据)中发生的。读数据并不会修改数据,多个线程读一个数据并不会对数据产生安全问题,也就是说只要没有写操作读锁可以被多个线程同时持有,这样就能大大提高读的效率了。

例如,贴吧,论坛,新闻类的业务场景,文章或帖子可以被评论或回复,这就是一个写入操作,这类业务场景的写入操作并不会很频繁,而浏览则是一个读取操作,这个操作是非常频繁的。
这种场景就很适合使用ReadWriteLock接口了,可以大大提高程序的执行效率。


Condition

Condition接口就是类似于Object类中的wait和notify,用来实现线程之间的通信。但是,Condition要比Object类中的wait和notify强大的多,可以实现精准唤醒,这个后面示例的时候再细说。

Lock接口中已经默认定义了newCondition()方法,返回的就是Condition类型的实例

Condition接口定义了如下方法
在这里插入图片描述

await 类似于 Object中的 wait 方法
signal 类似于 Object的 notify 方法


好了,到这里,我们就把java.util.concurrent.locks包中的接口大致了解了一遍,后面的文章我们来用用给我们提供的实现类。

下一篇:

JUC中的 ReentrantLock


如果你觉得本文对你有帮助,麻烦动动手指顶一下,可以帮助到更多的开发者,如果文中有什么错误的地方,还望指正,转载请注明转自喻志强的博客 ,谢谢!

以上是关于java.util.concurrent.locks 包中的接口和实现类的主要内容,如果未能解决你的问题,请参考以下文章

Java多线程与并发库高级应用-java5线程并发库

读Java性能权威指南(第2版)笔记28_线程和同步性能中

使用Lock锁实现线程同步

Java多线程之ReentrantLock与Condition

Java多线程与并发库高级应用-工具类介绍

java 多线程之ReentrantLock与condition