Java 中 Lock 接口详解:灵活强大的线程同步机制

在 Java 中,Lock 是一个接口,它提供了比 synchronized 关键字更灵活、更强大的线程同步机制。以下将详细介绍 Lock 接口及其实现类,以及它与 synchronized 相比的优点。

Lock 接口及其实现类介绍

Lock 接口

Lock 接口定义了一系列用于获取和释放锁的方法,主要方法如下:

  • void lock():获取锁,如果锁不可用,则当前线程将被阻塞,直到锁被释放。
  • void lockInterruptibly():可中断地获取锁,在获取锁的过程中,如果当前线程被中断,则会抛出 InterruptedException 异常。
  • boolean tryLock():尝试非阻塞地获取锁,如果锁可用,则获取锁并返回 true;否则返回 false。
  • boolean tryLock(long time, TimeUnit unit):在指定的时间内尝试获取锁,如果在该时间内锁可用,则获取锁并返回 true;否则返回 false。如果在等待过程中线程被中断,则会抛出 InterruptedException 异常。
  • void unlock():释放锁。
  • Condition newCondition():返回一个与该锁关联的 Condition 对象,用于实现线程间的等待 - 通知机制。

常见实现类

  • ReentrantLock:可重入锁,是 Lock 接口最常用的实现类。它支持与 synchronized 相同的可重入特性,即同一个线程可以多次获取同一把锁而不会被阻塞。
  • ReentrantReadWriteLock:读写锁,它维护了一对锁,一个读锁和一个写锁。多个线程可以同时获取读锁,但写锁是排他的,即同一时间只能有一个线程获取写锁,并且在写锁被持有时,其他线程不能获取读锁或写锁。

Lock 与 synchronized 对比的优点

1. 灵活性更高
  • 锁的获取和释放可分离:synchronized 是基于代码块或方法的,锁的获取和释放是隐式的,由 JVM 自动完成。而 Lock 接口的 lock() 和 unlock() 方法可以在不同的代码块中调用,这使得锁的获取和释放更加灵活。
    例如,在某些复杂的业务逻辑中,可能需要在不同的条件下释放锁,使用 Lock 可以很方便地实现这一点。
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class LockFlexibilityExample {private final Lock lock = new ReentrantLock();public void complexOperation() {lock.lock();try {// 执行一些操作if (someCondition()) {return;}// 继续执行其他操作} finally {lock.unlock();}}private boolean someCondition() {// 模拟条件判断return Math.random() > 0.5;}
}

在上述代码中,如果 someCondition() 方法返回 true,则会提前退出方法,但在 finally 块中仍然可以确保锁被释放。

  • 可中断的锁获取:Lock 接口提供了 lockInterruptibly() 方法,允许线程在获取锁的过程中被中断。而 synchronized 关键字在获取锁时是不可中断的,一旦线程进入阻塞状态,就只能等待锁被释放。这在某些场景下非常有用,例如当线程需要响应中断信号来执行其他操作时。
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class InterruptibleLockExample {private final Lock lock = new ReentrantLock();public void interruptibleTask() throws InterruptedException {lock.lockInterruptibly();try {// 执行任务System.out.println("获取到锁,执行任务");} finally {lock.unlock();}}public static void main(String[] args) {InterruptibleLockExample example = new InterruptibleLockExample();Thread thread = new Thread(() -> {try {example.interruptibleTask();} catch (InterruptedException e) {System.out.println("线程被中断");}});thread.start();// 中断线程thread.interrupt();}
}

在上述代码中,线程在获取锁的过程中被中断,会抛出 InterruptedException 异常,从而可以进行相应的处理。

2. 可实现公平锁

ReentrantLock 可以通过构造函数指定是否为公平锁。公平锁是指线程按照请求锁的顺序依次获取锁,避免了某些线程长时间得不到锁的情况。而 synchronized 关键字是非公平锁,线程获取锁的顺序是不确定的,可能会导致某些线程饥饿。

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class FairLockExample {private final Lock fairLock = new ReentrantLock(true);public void fairTask() {fairLock.lock();try {// 执行任务System.out.println(Thread.currentThread().getName() + " 获取到公平锁");} finally {fairLock.unlock();}}public static void main(String[] args) {FairLockExample example = new FairLockExample();for (int i = 0; i < 5; i++) {new Thread(example::fairTask, "Thread-" + i).start();}}
}

在上述代码中,ReentrantLock 被初始化为公平锁,线程会按照请求锁的顺序依次获取锁。

3. 支持多个条件变量

Lock 接口的 newCondition() 方法可以返回一个与该锁关联的 Condition 对象,一个 Lock 可以关联多个 Condition 对象,从而实现更精细的线程间通信。而 synchronized 关键字只能使用 wait()、notify() 和 notifyAll() 方法,这些方法是基于对象的监视器,只能实现简单的线程间等待 - 通知机制。

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class ConditionExample {private final Lock lock = new ReentrantLock();private final Condition notFull = lock.newCondition();private final Condition notEmpty = lock.newCondition();private final int[] buffer = new int[10];private int count = 0;private int in = 0;private int out = 0;public void put(int value) throws InterruptedException {lock.lock();try {while (count == buffer.length) {notFull.await();}buffer[in] = value;in = (in + 1) % buffer.length;count++;notEmpty.signal();} finally {lock.unlock();}}public int take() throws InterruptedException {lock.lock();try {while (count == 0) {notEmpty.await();}int value = buffer[out];out = (out + 1) % buffer.length;count--;notFull.signal();return value;} finally {lock.unlock();}}
}

在上述代码中,notFull 和 notEmpty 是两个不同的 Condition 对象,分别用于控制缓冲区满和缓冲区空的情况,实现了更精细的线程间通信。
总结
Lock 接口及其实现类提供了比 synchronized 关键字更灵活、更强大的线程同步机制,在需要更精细的锁控制、可中断的锁获取、公平锁和多个条件变量等场景下,Lock 是更好的选择。但 synchronized 关键字使用起来更加简单,在一些简单的同步场景下仍然是首选。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

实验分享|基于sCMOS相机科学成像技术的耐高温航空涂层材料损伤检测实验

1实验背景 航空发动机外壳的耐高温涂层材料在长期高温、高压工况下易产生微小损伤与裂纹&#xff0c;可能导致严重安全隐患。传统光学检测手段受限于分辨率与灵敏度&#xff0c;难以捕捉微米级缺陷&#xff0c;且检测效率低下。 某高校航空材料实验室&#xff0c;采用科学相机…

python训练营day40

知识点回顾&#xff1a; 彩色和灰度图片测试和训练的规范写法&#xff1a;封装在函数中展平操作&#xff1a;除第一个维度batchsize外全部展平dropout操作&#xff1a;训练阶段随机丢弃神经元&#xff0c;测试阶段eval模式关闭dropout 作业&#xff1a;仔细学习下测试和训练代码…

Baklib企业CMS全流程管控与智能协作

企业CMS全流程管控方案解析 现代企业内容管理中&#xff0c;全流程管控的实现依赖于对生产、审核、发布及迭代环节的系统化整合。通过动态发布引擎与元数据智能标记技术&#xff0c;系统可自动匹配内容与目标场景&#xff0c;实现标准化模板驱动的快速部署。针对多分支机构的复…

Qt程序添加调试输出窗口:CONFIG += console

目录 1.背景 2.解决方案 3.原理详解 4.控制台窗口的行为 5.条件编译&#xff08;仅调试模式显示控制台&#xff09; 6.替代方案 7.总结 1.背景 在Qt程序开发中&#xff0c;开发者经常遇到这样的困扰&#xff1a; 开发机上程序运行正常 发布到其他机器后程序无法启动 …

《江西棒球资讯》棒球运动发展·棒球1号位

联赛体系结构 | League Structure MLB模式 MLB采用分层体系&#xff08;大联盟、小联盟&#xff09;&#xff0c;强调梯队建设和长期发展。 MLB operates a tiered system (Major League, Minor League) with a focus on talent pipelines and long-term development. 中国现…

Python爬虫实战:研究Tornado框架相关技术

1. 引言 1.1 研究背景与意义 网络爬虫作为一种自动获取互联网信息的程序,在信息检索、数据挖掘、舆情分析等领域有着广泛的应用。随着互联网数据量的爆炸式增长,对爬虫的性能和效率提出了更高的要求。传统的同步爬虫在处理大量 URL 时效率低下,而异步爬虫可以显著提高并发…

Vue-列表过滤排序

列表过滤 基础环境 数据 persons: [{ id: "001", name: "刘德华", age: 19 },{ id: "002", name: "马德华", age: 20 },{ id: "003", name: "李小龙", age: 21 },{ id: "004", name: "释小龙&q…

JDK21深度解密 Day 9:响应式编程模型重构

【JDK21深度解密 Day 9】响应式编程模型重构 引言&#xff1a;从Reactor到虚拟线程的范式转变 在JDK21中&#xff0c;虚拟线程的引入彻底改变了传统的异步编程模型。作为"JDK21深度解密"系列的第91天&#xff0c;我们将聚焦于响应式编程模型重构这一关键主题。通过…

UE5打包项目设置Project Settings(打包widows exe安装包)

UE5打包项目Project Settings Edit-Project Settings- Packaging-Ini Section Denylist-Advanced 1&#xff1a;打包 2&#xff1a;高级设置 3&#xff1a;勾选创建压缩包 4&#xff1a;添加要打包地图Map的数量 5&#xff1a;选择要打包的地图Maps 6&#xff1a;Project-Bui…

Fastapi 学习使用

Fastapi 学习使用 Fastapi 可以用来快速搭建 Web 应用来进行接口的搭建。 参考文章&#xff1a;https://blog.csdn.net/liudadaxuexi/article/details/141062582 参考文章&#xff1a;https://blog.csdn.net/jcgeneral/article/details/146505880 参考文章&#xff1a;http…

java helloWord java程序运行机制 用idea创建一个java项目 标识符 关键字 数据类型 字节

HelloWord public class Hello{public static void main(String[] args) {System.out.print("Hello,World!");} }java程序运行机制 用idea创建一个java项目 建立一个空项目 新建一个module 注释 标识符 关键字 标识符注意点 数据类型 public class Demo02 {public st…

随机响应噪声-极大似然估计

一、核心原因&#xff1a;噪声机制的数学可逆性 在随机响应机制&#xff08;Randomized Response&#xff09;中使用极大似然估计&#xff08;Maximum Likelihood Estimation, MLE&#xff09;是为了从扰动后的噪声数据中无偏地还原原始数据的统计特性。随机响应通过已知概率的…

SMT贴片机工艺优化与效率提升策略

内容概要 现代电子制造领域中&#xff0c;SMT贴片机作为核心生产设备&#xff0c;其工艺优化与效率提升直接影响企业竞争力。本文聚焦设备参数校准、吸嘴选型匹配、SPI检测技术三大技术模块&#xff0c;结合生产流程重构与设备维护周期优化两大管理维度&#xff0c;形成系统性…

AI提示工程(Prompt Engineering)高级技巧详解

AI提示工程(Prompt Engineering)高级技巧详解 文章目录 一、基础设计原则二、高级提示策略三、输出控制技术四、工程化实践五、专业框架应用提示工程是与大型语言模型(LLM)高效交互的关键技术,精心设计的提示可以显著提升模型输出的质量和相关性。以下是经过验证的详细提示工…

光电设计大赛智能车激光对抗方案分享:低成本高效备赛攻略

一、赛题核心难点与备赛痛点解析 全国大学生光电设计竞赛的 “智能车激光对抗” 赛题&#xff0c;要求参赛队伍设计具备激光对抗功能的智能小车&#xff0c;需实现光电避障、目标识别、轨迹规划及激光精准打击等核心功能。从历年参赛情况看&#xff0c;选手普遍面临三大挑战&a…

【KWDB 创作者计划】_再热垃圾发电汽轮机仿真与监控系统:KaiwuDB 批量插入10万条数据性能优化实践

再热垃圾发电汽轮机仿真与监控系统&#xff1a;KaiwuDB 批量插入10万条数据性能优化实践 我是一台N25-3.82/390型汽轮机&#xff0c;心脏在5500转/分的轰鸣中跳动。垃圾焚烧炉是我的胃&#xff0c;将人类遗弃的残渣转化为金色蒸汽&#xff0c;沿管道涌入我的胸腔。 清晨&#x…

day23-计算机网络-1

1. 网络简介 1.1. 网络介质 网线&#xff1a;cat5,cat5e 六类网线&#xff0c;七类网线&#xff0c;芭蕾网线光纤&#xff1a;wifi&#xff1a;无线路由器&#xff0c;ap5G 1.2. 常见网线类型 1.2.1. 双绞线&#xff08;Twisted Pair Cable&#xff09;【最常用】 按性能主…

VR/AR 视网膜级显示破局:10000PPI 如何终结颗粒感时代?

一、传统液晶 “纱窗效应”&#xff1a;VR 沉浸体验的最大绊脚石 当用户首次戴上 VR 头显时&#xff0c;眼前密密麻麻的像素网格往往打破沉浸感 —— 这正是传统液晶显示在近眼场景下的致命缺陷。受限于 500-600PPI 的像素密度&#xff0c;即使达到 4K 分辨率&#xff0c;等效到…

2022---不重复版的数的划分-且范围太大

1.数的划分--数的划分--dfs剪枝-CSDN博客 2.范围太大&#xff0c;这题用dp 3.状态转移公式其中1是泛指 #include<bits/stdc.h> using namespace std; #define N 100011 typedef long long ll; typedef pair<int,int> pii; ll dp[2025][12]; int n,k; void solv…

day15 leetcode-hot100-29(链表8)

19. 删除链表的倒数第 N 个结点 - 力扣&#xff08;LeetCode&#xff09; 1.暴力法 思路 &#xff08;1&#xff09;先获取链表的长度L &#xff08;2&#xff09;然后再次遍历链表到L-n的位置&#xff0c;直接让该指针的节点指向下下一个即可。 2.哈希表 思路 &#xff0…