前言

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. python菜鸟教程学习1:背景性学习

    https://www.runoob.com/python3/python3-intro.html 优点 简单 -- Python 是一种代表简单主义思想的语言.阅读一个良好的 Python 程序就感 ...

  2. JS函数命名规范

    语法规范: 任何合法的javascript标识符都可以作为函数的名称. 约定俗成的内容:(非ECMAScript语法,但是为了便于开发者理解和识别,约定的函数命名规范.) 命名方法: 小驼峰式命名法 ...

  3. 工具博客转载-ftrace

    https://linux.cn/article-9273-1.html https://lwn.net/Articles/365835/ Documentation/trace/events.txt ...

  4. Mysql_笔记2018.1.28

    1.Mysql代码规范 1.关键字.函数名称大写 2.数据库名称.表名称.字段名称等全部小写 3.必须以分号;结尾 (或 \g) 2.记录mysql日志 开始记录 mysql> \T 日志地址 ...

  5. [原题复现][2020i春秋抗疫赛] WEB blanklist(SQL堆叠注入、handler绕过)

    简介 今天参加i春秋新春抗疫赛 一道web没整出来 啊啊啊 好垃圾啊啊啊啊啊啊啊  晚上看群里赵师傅的buuoj平台太屌了分分钟上线 然后赵师傅还分享了思路用handler语句绕过select过滤.. ...

  6. 直面秋招!非科班生背水一战,最终拿下阿里等大厂offer!

    前言 2020年已经接近到9月份了,很多粉丝朋友都对金九银十雀雀欲试了吧!也有很多朋友向我求教经验,因为我自己工作相对于稳定,在这里给大家分享一个粉丝朋友的经历,他作为一个曾经的菜鸡面试者,在不断的失 ...

  7. guitar pro系列教程(二十二):Guitar Pro在乐谱上的工作【二】

    我们在上一篇文章中给大家介绍了Guitar Pro的工作面板和音轨功能,今天我们将会给大家介绍Guitar Pro这款吉他谱学习软件得音频设置面板,在该面板中包含了声卡得选择.MIDI的输入输出及音轨 ...

  8. 本地VM安装虚拟机,使用xshell连接

    首先把VM设置成上面那样 在ubuntu里面安装ssh apt-get install openssh-server 启动服务 /etc/init.d/ssh startifconfig 查看ip x ...

  9. 通用于wps和excel的ntlm hashes窃取利用方式

    https://evi1cg.me/archives/Get_NTLM_Hashes.html介绍了通过Microsoft Office 窃取 NTLM Hashes. 不过这种插入方法不适用于wps ...

  10. Java命令行启动jar包更改默认端口以及配置文件的几种方式

    Java命令行启动jar包更改默认端口以及配置文件的几种方式 java -jar xxx.jar --server.port=8081 默认如果jar包没有启动文件,可以采用这种方式进行启动 java ...