Lock位于java.util.concurrent.locks包下,是一种线程同步机制,就像synchronized块一样。但是,Locksynchronized块更灵活、更复杂。

话不多说,我们直接来看官方文档对Lock接口相关概念及功能的描述,今天又是看英文文档,翻译理解的一天。

一、Lock继承关系

二、官方文档解读



三、Lock接口方法解读

void lock()

获取锁。如果锁不可用,则当前线程将出于线程调度目的而禁用,并处于休眠状态,直到获得锁为止。

void lockInterruptibly() throws InterruptedException;

如果当前线程未被中断,则获取锁。如果锁可用,则获取锁并立即返回。

如果锁不可用,出于线程调度目的,将禁用当前线程,该线程将一直处于休眠状态。

下面两种情形会让当前线程停止休眠状态:

  • 锁由当前线程获取。

  • 其他一些线程中断当前线程,并且支持对锁获取的中断。

当前线程出现下面两种情况时,将抛出InterruptedException,并清除当前线程的中断状态。

  • 当前线程在进入此方法时,已经设置为中断状态。

  • 当前线程在获取锁时被中断,并且支持对锁获取中断。

boolean tryLock();

尝试获取锁,如果锁处于空闲状态,则获取锁,并立即返回true。如果锁不可用,则立即返回false。

该方法的典型使用:

    Lock lock = ...;
//确保锁在被获取时被解锁
if (lock.tryLock()) {
try {
// manipulate protected state
} finally {
lock.unlock();
}
} else {
// perform alternative actions
}

boolean tryLock(long time, TimeUnit unit) throws

InterruptedException;

该方法为tryLock()的重载方法,两个参数分别表示为:

  • time:等待锁的最长时间
  • unit:时间单位

如果在给定的等待时间内是空闲的并且当前线程没有被中断,则获取锁。如果锁可用,则此方法立即获取锁并返回true,如果锁不可用,出于线程调度目的,将禁用当前线程,该线程将一直处于休眠状态。

下面三种情形会让当前线程停止休眠状态:

  • 锁由当前线程获取。

  • 其他一些线程中断当前线程,并且支持对锁获取的中断。

  • 到了指定的等待时间。

当前线程出现下面两种情况时,将抛出InterruptedException,并清除当前线程的中断状态。

  • 当前线程在进入此方法时,已经设置为中断状态。

  • 当前线程在获取锁时被中断,并且支持对锁获取中断。

如果指定的等待时间超时,则返回false值。如果时间小于或等于0,则该方法永远不会等待。

void unlock()

释放锁,与lock()、tryLock()、tryLock(long , TimeUnit)、lockInterruptibly()相对应。

Condition newCondition()

返回绑定到此锁实例的Condition实例。当前线程只有获得了锁,才能调用Condition实例的await()方法,并释放锁。

四、重要实现类ReentrantLock

顾名思义,ReentrantLock是重入锁,关于这个重入锁,之前涉及过一些知识,在这里做整合,并稍微地补充一下。

ReentrantLock位于java.util.concurrent(J.U.C)包下,是Lock接口的实现类。基本用法与synchronized相似,都具备可重入互斥的特性,但拥有扩展的功能。

RenntrantLock推荐的基本写法:

class X {
//定义锁对象
private final ReentrantLock lock = new ReentrantLock();
// ...
//定义需要保证线程安全的方法
public void m() {
//加锁
lock.lock();
try{
// 保证线程安全的代码
}
// 使用finally块保证释放锁
finally {
lock.unlock()
}
}
}

1、API层面的锁

ReentrantLock表现为API层面的互斥锁,通过lock()unlock()方法完成,是显式的,而synchronized表现为原生语法层面的互斥锁,是隐式的。

2、可重入的

重进入意味着:任意线程在获取到锁之后能够再次获取该锁而不会被锁阻塞synchronized和Reentrant都是可重入的,隐式显式之分。

实现可重入需要解决的两个关键部分:

  1. 锁需要去识别获取锁的线程是否是当前占据锁的线程,如果是的话,就成功获取。
  2. 锁获取一次,内部锁计数器需要加一,释放一次减一,计数为零表示为成功释放锁。

3、可公平的

关于锁公平的部分,官方文档是这样描述的(英文我就不贴了),词汇较简单,我试着翻译一下:

Reentrant类的构造函数接受一个可选的公平性参数fair。这时候就出现两种选择:

  • 公平的(fair == true):保证等待时间最长的线程优先获取锁,即FIFO。
  • 非公平的(fair == false):此锁不保证任何特定的访问顺序。

公平锁往往体现处的总体吞吐量比非公平锁要低,也就是更慢。

锁的公平性并不保证线程调度的公平性,但公平锁能够减少"饥饿"发生的概率。

需要注意的是:不定时的tryLock()方法不支持公平性设置。如果锁可用,即使其他线程等待时间比它长,它也会成功获得锁。

4、等待可中断

当持有线程长期不释放锁的时候,正在等待的线程可以选择放弃等待处理其他事情

5、锁绑定

一个ReentrantLock对象可以通过newCondition()同时绑定多个Condition对象


JDK1.6之前,ReentrantLock在性能方面是要领先于synchronized锁的,但是JDK1.6及之后版本实现了各种锁优化技术,可参考:

聊聊并发Java SE1.6中的Synchronized,后续性能改进会更加偏向于原生的synchronized。


参考资料:

《深入理解Java虚拟机》周志明

《Java并发编程的艺术》方腾飞

Java并发读书笔记:Lock与ReentrantLock的更多相关文章

  1. Java并发读书笔记:线程安全与互斥同步

    目录 导致线程不安全的原因 什么是线程安全 不可变 绝对线程安全 相对线程安全 线程兼容 线程对立 互斥同步实现线程安全 synchronized内置锁 锁即对象 是否要释放锁 实现原理 啥是重进入? ...

  2. Java并发读书笔记:如何实现线程间正确通信

    目录 一.synchronized 与 volatile 二.等待/通知机制 等待 通知 面试常问的几个问题 sleep方法和wait方法的区别 关于放弃对象监视器 三.等待通知典型 生产者消费者模型 ...

  3. Java并发读书笔记:JMM与重排序

    目录 Java内存模型(JMM) JMM抽象结构 重排序 源码->最终指令序列 编译器重排序 处理器重排序 数据依赖性 as-if-serial happens-before happens-b ...

  4. Java并发读书笔记:线程通信之等待通知机制

    目录 synchronized 与 volatile 等待/通知机制 等待 通知 面试常问的几个问题 sleep方法和wait方法的区别 关于放弃对象监视器 在并发编程中,保证线程同步,从而实现线程之 ...

  5. 《深入了解java虚拟机》高效并发读书笔记——Java内存模型,线程,线程安全 与锁优化

    <深入了解java虚拟机>高效并发读书笔记--Java内存模型,线程,线程安全 与锁优化 本文主要参考<深入了解java虚拟机>高效并发章节 关于锁升级,偏向锁,轻量级锁参考& ...

  6. java并发编程笔记(六)——AQS

    java并发编程笔记(六)--AQS 使用了Node实现FIFO(first in first out)队列,可以用于构建锁或者其他同步装置的基础框架 利用了一个int类型表示状态 使用方法是继承 子 ...

  7. java effective 读书笔记

    java effective 读书笔记 []创建和销毁对象 静态工厂方法 就是“封装了底层 暴露出一个访问接口 ” 门面模式 多参数时 用构建器,就是用个内部类 再让内部类提供构造好的对象 枚举 si ...

  8. 【多线程】Java并发编程:Lock(转载)

    原文链接:http://www.cnblogs.com/dolphin0520/p/3923167.html Java并发编程:Lock 在上一篇文章中我们讲到了如何使用关键字synchronized ...

  9. [转载] java并发编程:Lock(线程锁)

    作者:海子 原文链接: http://www.cnblogs.com/dolphin0520/p/3923167.html 出处:http://www.cnblogs.com/dolphin0520/ ...

随机推荐

  1. Idea 注册方式,亲测可用

    参考:https://www.cnblogs.com/aacoutlook/p/9036299.html 2018年3月 <License server>方式不能使用了,只好尝试<A ...

  2. 【转】8 个效果惊人的 WebGL/JavaScript 演示

    英文原文:9 IMPRESSIVE WEBGL JAVASCRIPT EFFECT SHOWCASE,翻译:iteye WebGL 是一种 3D 绘图标准,这种绘图技术标准允许把 JavaScript ...

  3. echarts设置数据在轴线上显示

    项目中遇到数据需要在右侧显示,如图,直接上代码: 1.需要在哪个轴上显示  就把那个轴写成一个数组 2.分别设置一下定位和数据即可(如下图红色部分) yAxis: [ { type: 'categor ...

  4. ASP.Net MVC 引用动态 js 脚本

    希望可以动态生成 js  发送给客户端使用. layout页引用: <script type="text/javascript" src="@Url.Action( ...

  5. Linux查看端口监听占用

    # 查看所有 netstat -ntlp # 过滤PORT8080 netstat -ntlp | grep 8080 -t # 仅显示tcp相关选项 -u # 仅显示udp相关选项 -n # 拒绝显 ...

  6. 数据可视化之Matplotlib的使用

    1.什么是数据可视化 数据可视化在量化分析当中是一个非常关键的辅助工具,往往我们需要通过可视化技术,对我们的数据进行更清晰的展示,这样也能帮助我们理解交易.理解数据.通过数据的可视化也可以更快速的发现 ...

  7. Falco 进入 CNCF Incubator 项目 | 云原生生态周报 Vol. 35

    作者 | 王思宇.陈洁.敖小剑 业界要闻 Falco 进入 CNCF Incubator 项目 原于 2018 年 8 月进入 sandbox,旨在 Kubernetes 运行时环境下支持配置规则来加 ...

  8. Webpack实战(二):webpack-dev-server的介绍与用法

    为什么要用webpack-dev-server 在开发中,我们都可以发现仅仅使用Webpack以及它的命令行工具来进行开发调试的效率并不高,每次编写好代码之后,我们需要执行npm run build命 ...

  9. 官方文档中文版!Spring Cloud Stream 快速入门

    本文内容翻译自官方文档,spring-cloud-stream docs,对 Spring Cloud Stream的应用入门介绍. 一.Spring Cloud Stream 简介 官方定义 Spr ...

  10. [bzoj1041] [洛谷P2508] [HAOI2008] 圆上的整点

    Description 求一个给定的圆(x^2+y^2=r^2),在圆周上有多少个点的坐标是整数. Input 只有一个正整数n,n<=2000 000 000 Output 整点个数 Samp ...