探索 java 中的各种锁

news/2024/10/3 16:19:59

Java 8+

-

 

序章

一直听说 java 的各种锁、(线程)同步机制,一直没有深入探索。

最近多看了几篇博文,算是理解的比较深入一些了,特写本文做个记录。ben发布于博客园

 

锁是什么?

一种用于 多个线程运行时协调的机制。

作用如下:ben发布于博客园

1、用于多线程之间同步,比如,执行顺序先后。

2、确保共享数据安全——堆内存数据、方法区数据、类的变量(static)、实例的变量。

 

隐式锁 vs 显式锁

1、synchronized 是我了解到的 唯一的 隐式锁,由 JVM 自行实现。

2、其它的为 显式锁,比如,interface Lock、interface ReadWriteLock、class StampedLock 及其实现类。

class ReentrantLock 实现了 interface Lock。ben发布于博客园

 

synchronized

java 关键字。由JVM实现锁机制。

和 class Object 的 wait()/notify()/notifyAll() 配合使用。

 

特性:

可重入锁。非公平锁。独享锁。悲观锁。

插个翻译:Reentrant lock. Unfair locks. Exclusive locks. Pessimistic locks.

 

随着 JVM 的发展,其锁机制也在逐步变化。ben发布于博客园

偏向锁、轻量级锁、重量级锁、锁膨胀 等概念都和它有关,这些概念 还涉及 synchronized 底层实现用到的 Java对象头——Monitor。

插个翻译:Biased locks, lightweight locks, heavyweight locks, lock expansion

参考资料:The Java® Virtual Machine Specification: Java SE 8 Edition (pdf 文档可以去 Java官网下载)

The Java® Language Specification: Java SE 8 Edition

修饰 类方法(static),使用 Class 对象 关联的 monitor。

修饰 实例方法,使用 实例 this 对象 关联的 monitor。ben发布于博客园

当然,还可以锁定代码块。在 14.19 The synchronized Statement 中 有介绍:

 

interface Lock

方法定义:

实现类:

最出名的就是下面提到的 class ReentrantLock 。

 

class ReentrantLock

实现了 interface Lock。

底层使用 abstract class AbstractQueuedSynchronizer(#重点) 实现。

 

特性:

可重入锁。默认非公平锁,可以 初始化为 公平锁。独享锁。悲观锁

类里面的 NonfairSync 为 非公平锁实现,而 FairSync 为公平锁。

 

单独使用(lock(), unlock()等),可以 保证 多线程时 共享数据安全。

结合 interface Condition 使用,可以 控制 多线程执行流程。

 

interface Condition

结构:

await() 类似于 Object 的 wait(),执行后,线程进入 阻塞状态。

signal()/signalAll() 类似于 Object 的 notify()/notify()All,唤醒阻塞的线程——一个或所有。

 

interface ReadWriteLock

适用于 读多写少 的场景。

提供了两个函数:

 

class ReentrantReadWriteLock

interface ReadWriteLock 的实现类。

底层使用 abstract class AbstractQueuedSynchronizer(#重点) 实现,内部类 Sync。

上面的内部类 ReadLock 和 WriteLock 都是实现了 Lock 接口的:

public static class ReadLock implements Lock, java.io.Serializable{private final Sync sync;
}public static class WriteLock implements Lock, java.io.Serializable {private final Sync sync;
}

类里面的 sync 属性是实现 锁机制的关键。

 

特性:

读锁 是 共享式,写锁 是 独享锁(排他锁)。可重入锁。

 

示例程序(通义千问):

ReadWriteLockExample.java
 // *** 来自 通义千问 ***
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.HashMap;
import java.util.Map;public class ReadWriteLockExample {private final Map<String, String> map = new HashMap<>();private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();private final ReentrantReadWriteLock.ReadLock readLock = lock.readLock();private final ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();public String get(String key) {readLock.lock();try {return map.get(key);} finally {readLock.unlock();}}public void put(String key, String value) {writeLock.lock();try {map.put(key, value);} finally {writeLock.unlock();}}public void remove(String key) {writeLock.lock();try {map.remove(key);} finally {writeLock.unlock();}}public static void main(String[] args) {ReadWriteLockExample example = new ReadWriteLockExample();// 创建多个读线程for (int i = 0; i < 5; i++) {final int threadId = i;new Thread(() -> {for (int j = 0; j < 10; j++) {String value = example.get("key" + (j % 5));System.out.println("Reader " + threadId + ": key" + (j % 5) + " = " + value);try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}}, "Reader-" + i).start();}// 创建一个写线程new Thread(() -> {for (int i = 0; i < 10; i++) {example.put("key" + i, "value" + i);System.out.println("Writer: Put key" + i + " = value" + i);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}, "Writer").start();}
}

程序说明:

 

class StampedLock

Since: 1.8,Java 8 才开始有的。

参考资料#2 提供了足够多的信息。

适用于 读操作远远大于写操作 的场景——更胜于 前面的 interface ReadWriteLock。

 

特性:

乐观读锁

 

类:

Node 类:

 

示例程序(通义千问):

StampedLockExample.java
// 来自 通义千问import java.util.concurrent.locks.StampedLock;
import java.util.HashMap;
import java.util.Map;public class StampedLockExample {private final Map<String, String> map = new HashMap<>();private final StampedLock lock = new StampedLock();public String getOptimistic(String key) {long stamp = lock.tryOptimisticRead();String value = map.get(key);// 检查是否有写操作发生if (!lock.validate(stamp)) {// 升级为悲观读锁stamp = lock.readLock();try {value = map.get(key);} finally {lock.unlockRead(stamp);}}return value;}public String get(String key) {long stamp = lock.readLock();try {return map.get(key);} finally {lock.unlockRead(stamp);}}public void put(String key, String value) {long stamp = lock.writeLock();try {map.put(key, value);} finally {lock.unlockWrite(stamp);}}public void remove(String key) {long stamp = lock.writeLock();try {map.remove(key);} finally {lock.unlockWrite(stamp);}}public static void main(String[] args) {StampedLockExample example = new StampedLockExample();// 创建多个读线程for (int i = 0; i < 5; i++) {final int threadId = i;new Thread(() -> {for (int j = 0; j < 10; j++) {String value = example.getOptimistic("key" + (j % 5));System.out.println("Reader " + threadId + ": key" + (j % 5) + " = " + value);try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}}, "Reader-" + i).start();}// 创建一个写线程new Thread(() -> {for (int i = 0; i < 10; i++) {example.put("key" + i, "value" + i);System.out.println("Writer: Put key" + i + " = value" + i);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}, "Writer").start();}
}

说明:

 

小结

探索 期间,遇到了 AbstractQueuedSynchronizer、Unsafe 等,还需要进一步探索(看更多博文呗)。

整个 java.util.concurrent.locks 包 下的内容:

 

疑问:

有了这些锁机制,为什么还需要 class CountDownLatch、class CyclicBarrier、class Semaphore 等呢?它们和 多线程开发 有什么关系?

还有就是 java.util.concurrent.atomic 下的东西。

 

---END---

 

本文链接:

https://www.cnblogs.com/luo630/p/18445669/java-locks-note

 

参考资料

1、java里的锁总结(synchronized隐式锁、Lock显式锁、volatile、CAS)
https://www.cnblogs.com/lifegoeson/p/13683785.html
posted @ 2020-09-17 10:38  Life_Goes_On

2、深入了解Java中的锁机制
2024-03-04
https://developer.aliyun.com/article/1449639

3、一文彻底搞懂面试中常问的各种“锁”
https://www.cnblogs.com/coding-night/p/10657892.html
posted on 2019-04-05 08:24  深夜里的程序猿

4、

 

ben发布于博客园

ben发布于博客园

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/67391.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

#1118 - Row size too large. The maximum row size for the used table type, not counting BLOBs

这个问题表示在MySQL中,表的一行数据大小超过了最大限制65535字节。这通常是因为表中的某些字段过长导致的。下面是一些解决方法:调整字段类型:将一些较大的字段改为TEXT或BLOB类型。这些类型的存储方式不同于普通字段,可以避免占用过多的行内空间。拆分字段:如果某个字段…

ssh进Windows的一次尝试

1. 配置端口映射 https://chmlfrp.cn/ 1.2 进入管理面板 1.3实名认证(网站声称是阿里云) 1.4下载客户端1.5进入隧道列表添加隧道1.5进入“配置文件”中选择节点生成配置文件并复制 1.6 设置frpc.ini 删除frpc.ini文件,重新建立并粘贴生成的配置文件 1.7 启动 在当前目录下打…

SpringBoot项目使用yml文件链接数据库异常

SpringBoot使用properties连接数据库时没有出现问题 SpringBoot使用yml连接数据库时出现:Unable to connect to Redis 并在报错信息中出现:发现是用户或者密码出现问题 通过查询知道yml是区分数据类型的,所以如果用户名或者密码是数字的话,就要注意将密码用双引号括起来,将…

行列式求法和矩阵树定理

1.矩阵树定理 无向图,有n个点,如果说i-j之间有连边,那么矩阵g[i][j]=g[j][i]=-1(i-j之间的边的数量),否则值为0 矩阵上对角线上的值为该点的度数,g[i][i]=d[i]; 生成树个数:任选i,去掉i行i列之后的行列式的值 生成树的权值=边权的乘积,所有生成树的权值之和? i-j之间右边,g[i]…

git 代码提交规范 commitLink

commitLink 是一个 git 代码提交规范工具,能规范团队成员代码必须按照 规范提交 1、安装依赖:npm install --save-dev @commitlint/config-conventional @commitlint/cli依赖安装完成之后,会生成一个 commitLink.config.js 配置文件 2、安装 kusky ( mpn install .husky/co…

RUST所有权相关问题

先介绍一下RUST的所有权规则: 1.Rust 中的每一个值都有一个所有者(owner)。 2.值在任一时刻有且只有一个所有者。 3.当所有者(变量)离开作用域,这个值将被丢弃。 变量与数据交互的方式包括两种:移动和克隆。 移动就是转交值的所有权,如let x=y(x的类型未实现Copy trait)…

GoogLeNet训练CIFAR10[Pytorch+训练信息+.pth文件]

0 引言GoogLeNet,它是一种深度卷积神经网络,由Google研究人员在2014年提出,用于图像识别任务。 CIFAR-10是一个常用的图像识别数据集,包含10个类别,每个类别有6000张32x32的彩色图像。 本文使用Pycharm及Pytorch框架搭建GoogLeNet神经网络框架,使用CIFAR10数据集训练模型…

IntelliJ IDEA中,代码折叠(Code Folding)功能 取消 默认的 方法体自动展开

默认情况下 方法体 代码折叠后,再次启动 IDEA 时 会自动展开 取消 下面的多选框 则 下次启动不会自动展开