前言

Java 的锁实现,有 Synchronized 和 Lock。上一篇文章深入分析了 Synchronized 的实现原理:由Java 15废弃偏向锁,谈谈Java Synchronized 的锁机制

本篇文章深入分析 Lock 的实现,以及对比其与 Synchronized 的不同。

Synchronized 与 Lock 的对比

  • 实现方式:Synchronized 由 JVM 实现;Lock 由 Java 底层代码实现
  • 锁获取:Synchronized 是 JVM 隐式获取,不用 Java 代码;Lock 由 Java 代码实现,有多种获取方式
  • 锁的释放:Synchronized 是 JVM 隐式释放,不用 Java 代码;Lock 可通过 Lock.unlock(),在 finally 中释放
  • 锁的类型:Synchronized 是非公平、可重入的Lock 是非公平性、公平性、可重入的
  • 锁的中断:Synchronized 不支持中断,Lock 支持中断

实现原理

Lock 是一个接口类,其接口方法定义:

  • lock():获取锁
  • lockInterruptibly():如果当前线程未被中断,则获取锁,可以响应中断
  • tryLock():仅在调用时锁为空闲状态才获取该锁,可以响应中断
  • tryLock(long time, TimeUnit unit):如果锁在给定的等待时间内空闲,并且当前线程未被中断,则获取锁
  • unlock():释放锁
  • newCondition():返回绑定到此 Lock 实例的新 Condition 实例

基础原理就不赘述了,Lock 接口的常用类:

  • ReentrantLock(重入锁)
  • ReentrantReadWriteLock(可重入的读写锁)

其都是依赖 AQS 实现的。AQS 类结构中包含一个基于链表实现的等待队列(CLH 队列),用于存储所有阻塞的线程,AQS 中还有一个 state 变量,表示加锁状态。

ReentrantLock

ReentrantReadWriteLock

ReentrantLock 是独占锁,对于同一份数据,如果一个线程读数据,另一个线程在写数据,那么读到的数据与最终的数据可能不一致。

在实际的业务场景中,读操作远远大于写操作。在多线程编程中,读操作不会修改共享资源的数据。针对读多写少的场景,我们可以使用 ReentrantReadWriteLock 来优化,ReentrantReadWriteLock 内部维护了 2 个锁:读锁 ReadLock,写锁 WriteLock

规则简单概括为:

  • 如果写锁没有被占用,就可以获取读锁
  • 如果读锁没有被占用,才可以获取写锁

下面的测试代码,因为读锁和写锁是同时 lock 的,所以会死锁。

@Test
public void testReadWriteLock() {
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
lock.readLock().lock();
lock.writeLock().lock();
System.out.println("Hello");
lock.readLock().unlock();
lock.writeLock().unlock();
}

StampedLock

上述 ReentrantReadWriteLock 会有一个问题:在读很多,写很少的情况下,线程会因一直无法获取到锁而处于等待状态。

在 JDK 1.8 中,Java 提供了 StampedLock,有三种模式:

  • 悲观读
  • 乐观读

一个写线程获取写锁,通过 WriteLock 获取票据 stamp,WriteLock 是一个独占锁,unlockWrite 需要传递参数 stamp。

不一样的地方在于读过程。线程会先通过乐观锁 tryOptimisticRead 获取票据 stamp,如果当前没有线程持有写锁,则会返回一非 0 的 stamp 信息。线程获取该 stamp 后,会拷贝一份共享资源到房发展。

之后方法还需要调用 validate,验证之前调用 tryOptimisticRead 返回的 stamp 在当前是否有其它线程持有了写锁,如果是,那么 validate 会返回 0,升级为悲观锁;否则就可以使用该 stamp 版本的锁对数据进行操作。

总结

相比于 Synchronized 同步锁,Lock 实现的锁更加灵活:

  • 可以分为读写锁,优化读大于写的场景
  • 可以中断
  • 可以超时
  • 可以区分公平性

公众号

coding 笔记、点滴记录,以后的文章也会同步到公众号(Coding Insight)中,希望大家关注_

代码和思维导图在 GitHub 项目中,欢迎大家 star!

深入分析 Java Lock 同步锁的更多相关文章

  1. Lock同步锁

    Lock同步锁 一.前言 在Java 5.0 之前,协调共享对象的访问时可以使用的机制只有synchronized 和volatile .Java 5.0 后增加了一些新的机制,但并不是一种替代内置锁 ...

  2. JUC--Callable 以及Lock同步锁

    /** * 一.创建执行线程的方式三:实现Callable接口.相较于实现Runnable接口方式,方法可以有返回值,并且可以抛出异常 * 二.callable 需要FutureTask实现类的支持. ...

  3. 7.生产者消费者 案例 (使用Lock 同步锁 方式,使用Condition完成线程之间的通信)

    /* * 生产者消费者 案例 (使用Lock 同步锁 方式,使用Condition完成线程之间的通信) * */ public class TestProductorAndConsumerForLoc ...

  4. Java并发编程之Lock(同步锁、死锁)

    这篇文章是接着我上一篇文章来的. 上一篇文章 同步锁 为什么需要同步锁? 首先,我们来看看这张图. 这是一个程序,多个对象进行抢票. package MovieDemo; public class T ...

  5. Lock同步锁--线程同步

    Lock-同步锁 Lock是java5提供的一个强大的线程同步机制--通过显示定义同步锁对象来实现同步.Lock可以显示的加锁.解锁.每次只能有一个线程对lock对象加锁. Lock有ReadLock ...

  6. Java多线程同步锁的理解

    java主要通过synchronized的关键字来实现的.让我们从一个买票程序说起吧. package com.day04; /** * * @author Administrator 问题描述:使用 ...

  7. Java线程同步锁

    把synchronized当作函数修饰符时,示例代码如下: Public synchronized void method(){ //-. } 这也就是同步方法,那这时synchronized锁定的是 ...

  8. java提高同步锁的几点建议

    1.减少锁的持有时间,只对关键的代码块加锁,减少synchronized锁内部的无关模块: 2.减小锁粒度,如Collections.synchronizedMap(map)返回线程安全的map会锁整 ...

  9. python笔记9 线程进程 threading多线程模块 GIL锁 multiprocessing多进程模块 同步锁Lock 队列queue IO模型

    线程与进程 进程 进程就是一个程序在一个数据集上的一次动态执行过程.进程一般由程序.数据集.进程控制块三部分组成.我们编写的程序用来描述进程要完成哪些功能以及如何完成:数据集则是程序在执行过程中所需要 ...

随机推荐

  1. UNP——原始套接字

    1.原始套接字的用处 使用原始套接字可以构造或读取网际层及其以上报文. 具体来说,可以构造 ICMP, IGMP 协议报文,通过开启 IP_HDRINCL 套接字选项,进而自定义 IPv4首部. 2. ...

  2. parted命令采用gpt分区过程

    Gpt无分区限制,故只有主分区,无扩展分区和逻辑分区.分区直接按容量算,不按柱面算. 查看分区:parted -l 将分区表类型转换为gpt.: 主要命令mklabel gpt 对sdc盘分区: [r ...

  3. 流量控制--5.Classless Queuing Disciplines (qdiscs)

    Classless Queuing Disciplines (qdiscs) 本文涉及的队列规则(Qdisc)都可以作为接口上的主qdisc,或作为一个classful qdiscs的叶子类.这些是L ...

  4. tomcat设置好环境变量,依然无法通过cmd startup命令启动

    Windows环境下JDK安装与环境变量配置详细的图文教程 https://www.cnblogs.com/liuhongfeng/p/4177568.html   Windows环境下maven 环 ...

  5. Python_错误调试2018.3.17【待完善】

    异常处理 几个提示信息: notice 注意 warning 警告 error 错误 debug 调试 错误处理 1.Try语句 try execpt 2.print() 3.assert断言,当满足 ...

  6. Distributing Custom Apps

    Distributing Custom Apps 分配自定义应用程序 November 10, 2020 2020年11月10日 Custom apps let you meet the unique ...

  7. C#推流RTMP,摄像头、麦克风、桌面、声卡(附源码)

    这段时间一直都在研究推流的技术,经过断断续续将近两个月的摸索实践,终于能稳定地推流了. 这个demo的主要功能就是将采集到的摄像头或桌面的视频.以及麦克风或声卡的音频数据推到Nginx-RTMP服务器 ...

  8. The Life out of coding_Employment_01

    1.工作与个人价值 软技能读书笔记第一篇:--From 安晓辉 内生涯与外生涯 内生涯包括知识.技能.工作经验.心理素质.内心情感.行为习惯.视野.观念.职业心态.职业成熟度.心灵成长. 外生涯包括职 ...

  9. MathType中怎么编辑韩文字符

    用MathType编辑公式,所涉及到符号与字母一般都是英文字母与数字,或者使用希腊字母,当然还有很多使用中文的情况.但是不仅如此,我们在使用MathType时,除了这些字符之外,还可以输入韩文或者日文 ...

  10. window安装elasticsearch和kibana

    本次测试安装5.1.1版本 es下载地址:https://www.elastic.co/downloads/past-releases/elasticsearch-5-1-1 选择zip kibana ...