当前位置: 首页 > news >正文

JUC并发编程_Lock锁

JUC并发编程_Lock锁

      • 1、Lock锁介绍
      • 2、主要方法
      • 3、与 synchronized 的区别
      • 4、Condition 使用示例


1、Lock锁介绍

Java中的 Lock 锁是 java.util.concurrent.locks 包下的一个接口,它提供了比 synchronized 关键字更灵活的锁定机制。


2、主要方法

  • lock():获取锁。如果锁不可用,则当前线程将被禁用,直到锁变为可用。
  • tryLock():尝试获取锁,如果锁可用,则获取锁并立即返回true;如果锁不可用,则立即返回false,并且当前线程不会被禁用。
  • tryLock(long time, TimeUnit unit):尝试获取锁,如果锁在给定的等待时间内可用,并且当前线程未被中断,则获取锁。
  • lockInterruptibly():用于以可中断的方式获取锁。这个方法与 lock() 方法的主要区别在于,当线程尝试获取锁而锁已被其他线程持有时,lock() 方法会使线程在锁上无限期地等待,直到锁变为可用;而 lockInterruptibly() 方法允许等待锁的线程在等待过程中响应中断
  • unlock():释放锁
  • newCondition():返回绑定到此 Lock 实例的新 Condition 实例。Condition 提供了与Object监视器方法(如wait、notify和notifyAll)类似的功能,但与Lock实例相关联。

3、与 synchronized 的区别

  • 灵活性:Lock 锁提供了比 synchronized 更灵活的锁定操作。例如,tryLock 方法允许在不能立即获取锁时不会使线程进入阻塞状态,而是返回一个布尔值。
  • 可中断性:Lock 锁支持获取锁时的中断响应,而 synchronized 不支持。这意味着如果某个线程在等待锁的过程中被中断,它可以立即响应中断,而不是无限期地等待
  • 超时尝试:Lock 锁允许尝试获取锁时设置超时时间,如果在这个时间内锁没有被获取到,则线程可以放弃等待,去做其他事情
  • 条件变量:Lock 锁提供了 Condition 接口,支持多个条件变量,而 synchronized 关键字则只有一个条件变量(即对象监视器)
  • 锁的获取和释放:synchronized 锁的获得和释放都是自动的,Lock 锁需要手动获取和释放。
  • 锁的公平性:synchronized 锁是非公平锁,Lock 锁默认是非公平锁的,但可以通过构造函数传参改变为公平锁。
  • 精准唤醒:synchronized 的唤醒机制是基于 wait/notify 或 notifyAll 方法的,其中 notify 方法只能随机唤醒等待队列中的一个线程,无法做到精准唤醒。Lock 锁可以通过操作不同 Condition 实例的 signal() 方法实现精准唤醒。

4、Condition 使用示例

创建一个简单的生产者-消费者场景,其中使用 ReentrantLock(Lock接口的一个实现)和 Condition 来控制对共享资源的访问

import java.util.LinkedList;  
import java.util.Queue;  
import java.util.concurrent.locks.Condition;  
import java.util.concurrent.locks.Lock;  
import java.util.concurrent.locks.ReentrantLock;  public class ProducerConsumerExample {  private final Queue<Integer> queue = new LinkedList<>();  private final int capacity = 10;  private final Lock lock = new ReentrantLock();  private final Condition notFull = lock.newCondition();  private final Condition notEmpty = lock.newCondition();  public void produce(int value) throws InterruptedException {  lock.lock();  try {  while (queue.size() == capacity) {  // 当队列满时,生产者等待  notFull.await();  }  queue.add(value);  System.out.println("Produced: " + value);  // 通知消费者队列中有新元素  notEmpty.signal();  } finally {  lock.unlock();  }  }  public void consume() throws InterruptedException {  lock.lock();  try {  while (queue.isEmpty()) {  // 当队列空时,消费者等待  notEmpty.await();  }  int value = queue.poll();  System.out.println("Consumed: " + value);  // 通知生产者队列中有空间  notFull.signal();  } finally {  lock.unlock();  }  }  public static void main(String[] args) {  ProducerConsumerExample example = new ProducerConsumerExample();  // 创建生产者和消费者线程  Thread producer = new Thread(() -> {  for (int i = 0; i < 20; i++) {  try {  example.produce(i);  Thread.sleep(100); // 模拟耗时操作  } catch (InterruptedException e) {  Thread.currentThread().interrupt();  }  }  });  Thread consumer = new Thread(() -> {  for (int i = 0; i < 20; i++) {  try {  example.consume();  Thread.sleep(150); // 模拟耗时操作  } catch (InterruptedException e) {  Thread.currentThread().interrupt();  }  }  });  // 启动线程  producer.start();  consumer.start();  }  
}
  • await() 方法

await() 方法是 Condition 接口中的一个方法,它会使当前线程进入等待状态(即阻塞),直到其他线程调用该Condition 的 signal() 或 signalAll() 方法,或者当前线程被中断,或者等待过程中发生了 InterruptedException 异常。

在调用 await() 方法之前,当前线程必须已经获得了与 Condition 相关联的锁。调用 await() 方法后,当前线程会释放这个锁,并进入等待状态。当线程从 await() 方法返回时,它必须重新获取这个锁才能继续执行。

在 ProducerConsumerExample 的 produce 方法中,当队列满时,生产者线程会调用 notFull.await() 等待,直到有消费者线程消费了队列中的元素并调用了 notFull.signal() 或 notFull.signalAll() 方法。

在 consume 方法中,当队列空时,消费者线程会调用 notEmpty.await() 等待,直到有生产者线程生产了新的元素并调用了 notEmpty.signal() 或 notEmpty.signalAll() 方法。

  • signal() 方法

signal() 方法是 Condition 接口中的一个方法,它用于唤醒等待在该 Condition 上的单个线程(如果有的话)。在调用 signal() 方法之前,当前线程必须已经获得了与 Condition 相关联的锁。

在 ProducerConsumerExample 的 produce 方法中,当生产者线程成功地将一个元素添加到队列中后,它会调用 notEmpty.signal() 来唤醒可能正在等待的消费者线程(如果有的话),以便消费者线程可以消费这个新元素。

在 consume 方法中,当消费者线程成功地从队列中取出一个元素后,它会调用 notFull.signal() 来唤醒可能正在等待的生产者线程(如果有的话),以便生产者线程可以继续生产新的元素。

需要注意的是,signal() 方法只会唤醒等待队列中的一个线程,而 signalAll() 方法会唤醒等待队列中的所有线程。在这个例子中,我们使用了 signal() 方法,因为生产者-消费者问题通常只需要唤醒一个等待的线程(生产者唤醒消费者,或消费者唤醒生产者)。然而,在某些情况下,使用 signalAll() 可能更合适,特别是当你不确定应该唤醒哪个线程时。但是,使用 signalAll() 可能会导致不必要的线程唤醒和竞争,从而影响性能。

相关文章:

JUC并发编程_Lock锁

JUC并发编程_Lock锁 1、Lock锁介绍2、主要方法3、与 synchronized 的区别4、Condition 使用示例 1、Lock锁介绍 Java中的 Lock 锁是 java.util.concurrent.locks 包下的一个接口&#xff0c;它提供了比 synchronized 关键字更灵活的锁定机制。 2、主要方法 lock()&#xff1a…...

Unity中的功能解释(数学位置相关和事件)

向量计算 Vector3.Slerp&#xff08;起点坐标&#xff0c;终点坐标&#xff0c;t&#xff09;&#xff0c;可是从起点坐标以一个圆形轨迹到终点坐标&#xff0c;有那么多条轨迹&#xff0c;那怎么办 Vector3.Slerp 进行的是沿球面插值&#xff0c;因此并不是沿着严格的“圆形…...

ElementPlus---Timeline 时间线组件使用示例

介绍 使用ElementPlus时间线组件在后台首页实现通知公告列表展示&#xff0c;使用Vue3开发。 实现代码 Vue3代码 <el-timeline><el-timeline-itemstyle"max-width: 600px"v-for"(activity, index) in activities":key"index":times…...

推荐4款2024年大家都在用的高质量翻译器。

翻译器在我们的生活中有着很重要的作用&#xff0c;不管是我们在学习还是工作&#xff0c;生活娱乐&#xff0c;出国旅游等场合都会派上用场&#xff0c;它是我们解决沟通的障碍&#xff0c;提高阅读效率的好帮手。我自己使用的翻译器有很多&#xff0c;可以给大家列举几款特别…...

Mybatis 返回 Map 对象

一、场景介绍 假设有如下一张学生表&#xff1a; CREATE TABLE student (id int NOT NULL AUTO_INCREMENT COMMENT 主键,name varchar(100) NOT NULL COMMENT 姓名,gender varchar(10) NOT NULL COMMENT 性别,grade int NOT NULL COMMENT 年级,PRIMARY KEY (id) ) ENGINEInnoD…...

Vue3(三)路由基本使用、工作模式(history,hash)、query传参和param传参、props配置、编程式路由导航

文章目录 一、路由的基本使用二、路由器的工作模式三、RouterLink中to的两种写法四、嵌套路由五、路由传参1. query传参2. params传参 六、路由的propos配置七、编程式路由导航 一、路由的基本使用 安装&#xff1a;npm i vue-router 在src/pages文件下&#xff0c;创建三个路…...

TypeScript概念讲解

简单来说&#xff0c;TypeScript 是 JavaScript 的一个超集&#xff0c;支持 ECMAScript 6 标准&#xff1b; TypeScript 由微软开发的自由和开源的编程语言&#xff1b; TypeScript 设计目标是开发大型应用&#xff0c;它可以编译成纯 JavaScript&#xff0c;编译出来的 Jav…...

C++ | Leetcode C++题解之第437题路径总和III

题目&#xff1a; 题解&#xff1a; class Solution { public:unordered_map<long long, int> prefix;int dfs(TreeNode *root, long long curr, int targetSum) {if (!root) {return 0;}int ret 0;curr root->val;if (prefix.count(curr - targetSum)) {ret pref…...

回复《对话损友 2》

回复《对话损友 2》 承蒙贵人挂念&#xff0c;亦感激贵人给予这般交流的契机&#xff08;对话损友 2 -- 回复-CSDN博客&#xff09;。我自身也一直期望能留存些岁月的痕迹&#xff0c;然而却常困惑于不知哪些事物值得铭记&#xff0c;哪些又应被永远忘却。 随着时光流转&#x…...

MySQL - 运维篇

一、日志 1. 错误日志 2. 二进制日志 3. 查询日志 记录了所有的增删改查语句以及DDL语句 4. 慢查询日志 二、主从复制 1. 概述 2. 原理 3. 搭建 三、分库分表 1. 介绍 2. Mycat概述 3. Mycat入门 4. Mycat配置 5. Mycat分片 6. Mycat管理及监控 四、读写分离 1. 介绍 2. 一…...

WebGIS开发及市面上各种二三维GIS开发框架对比分析

GIS前端开发是现代WebGIS应用开发中非常重要的一环&#xff0c;通过前端开发框架&#xff0c;可以实现地图展示、交互、分析等功能。本文将介绍当前市面上常用的GIS前端开发框架&#xff0c;并进行对比分析。 Leaflet Leaflet是一款轻量级的开源地图库&#xff0c;它提供了丰…...

[论文精读]TorWard: Discovery, Blocking, and Traceback of Malicious Traffic Over Tor

期刊名称&#xff1a;IEEE Transactions on Information Forensics and Security 发布链接&#xff1a;TorWard: Discovery, Blocking, and Traceback of Malicious Traffic Over Tor | IEEE Journals & Magazine | IEEE Xplore 中文译名&#xff1a;TorWard&#xff1a;…...

pytest - 多线程提速

import timedef test1_test1():time.sleep(1)assert 1 1, "11"def test1_test2():time.sleep(1)assert 1 1, "11" 上面2个函数&#xff0c;执行情况&#xff1a; 正常执行时&#xff0c;花费 2.08s2个进程执行时&#xff0c;花费 1.18s2个线程执行时&a…...

python中logging的用法

logging.error 是 Python logging 模块中的一个方法&#xff0c;专门用于记录错误级别&#xff08;ERROR&#xff09;的日志信息。logging 模块是 Python 提供的标准日志工具&#xff0c;用于生成各种级别的日志消息&#xff0c;并支持日志的格式化和存储。 logging.error 的基…...

【YOLO目标检测车牌数据集】共10000张、已标注txt格式、有训练好的yolov5的模型

目录 说明图片示例 说明 数据集格式&#xff1a;YOLO格式 图片数量&#xff1a;10000&#xff08;2000张绿牌、8000张蓝牌&#xff09; 标注数量(txt文件个数)&#xff1a;10000 标注类别数&#xff1a;1 标注类别名称&#xff1a;licence 数据集下载&#xff1a;车牌数据…...

gdb xterm 调试 openmpi 程序

1&#xff0c;编写编译一个openmpi程序 迭代计算 PI 的源程序&#xff1a; pi_reduce.c #include <stdio.h>#include <math.h> #include <mpi.h>double f(double); double f(double x) {return (4.0/(1.0x*x)); }int main(int argc, char* argv[]) {int d…...

【STM32】江科大STM32笔记汇总(已完结)

STM32江科大笔记汇总 STM32学习笔记课程简介(01)STM32简介(02)软件安装(03)新建工程(04)GPIO输出(05)LED闪烁& LED流水灯& 蜂鸣器(06)GPIO输入(07)按键控制LED 光敏传感器控制蜂鸣器(08)OLED调试工具(09)OLED显示屏(10)EXTI外部中断(11)对射式红外传感器计次 旋转编码器…...

Java基础扫盲(二)

想看Java基础扫盲&#xff08;一&#xff09;的可以观看我的上篇文章Java基础扫盲 目录 String为什么设计为不可变的 String有长度限制吗 为什么JDK9将String的char[]改为byte[] 泛型中K,T,V,E,Object,?等都代表什么含义 怎么修改一个类中使用了private修饰的String类型…...

兼容React的刮刮乐完整代码实现

需要兼容React的刮刮乐完整代码实现 在现代Web开发中&#xff0c;React作为一种流行的前端框架&#xff0c;为开发者提供了构建动态界面的强大工具。刮刮乐效果作为一种趣味性的用户交互&#xff0c;能够显著提升用户体验和参与度。本文将详细介绍如何在React项目中实现一个兼…...

PHP程序如何实现限制一台电脑登录?

PHP程序如何实现限制一台电脑登录&#xff1f; 可以使用以下几种方法&#xff1a; 1. IP地址限制&#xff1a;在PHP中&#xff0c;可以通过获取客户端的IP地址&#xff0c;然后与允许登录的IP地址列表进行比对。如果客户端的IP地址不在列表中&#xff0c;就禁止登录。 “php $…...

一键部署工具OneClickCopaw:从脚本化到容器化的自动化实践

1. 项目概述与核心价值最近在折腾一些自动化部署和配置管理的工作&#xff0c;发现一个挺有意思的项目&#xff0c;叫iwanglei1/OneClickCopaw。光看这个名字&#xff0c;可能有点摸不着头脑&#xff0c;但如果你也经常需要在不同环境里快速复制一套开发或测试环境&#xff0c;…...

从零构建高频无线传输系统:调幅技术实战解析

1. 调幅无线传输系统入门指南 第一次接触调幅无线传输系统时&#xff0c;我也被各种专业术语搞得一头雾水。简单来说&#xff0c;调幅(AM)就是通过改变载波信号的幅度来传递信息的技术。想象一下快递员送包裹&#xff1a;载波就像快递车&#xff0c;而我们要发送的信息就是包裹…...

DRAM计算内存的电源传输网络优化策略

1. DRAM计算内存中的电源传输网络挑战与优化在数据密集型应用爆炸式增长的今天&#xff0c;传统冯诺依曼架构面临严峻的"内存墙"挑战。计算内存&#xff08;Compute-in-Memory, CIM&#xff09;技术通过在内存内部执行计算任务&#xff0c;从根本上改变了数据处理范式…...

Argo CD 集成 Helmfile 插件:实现 GitOps 下复杂应用声明式部署

1. 项目概述与核心价值如果你正在使用 Argo CD 管理 Kubernetes 集群&#xff0c;并且你的应用清单是由 Helmfile 来编排的&#xff0c;那么travisghansen/argo-cd-helmfile这个项目很可能就是你一直在寻找的“粘合剂”。简单来说&#xff0c;它是一个专门为 Argo CD 设计的 He…...

告别驱动开发:手把手教你用himm工具在用户空间玩转Hi3516的GPIO

用户空间高效操控Hi3516 GPIO&#xff1a;himm工具实战指南 在嵌入式开发领域&#xff0c;传统的内核驱动开发往往需要经历漫长的编译、加载和调试周期。对于快速硬件验证和原型开发而言&#xff0c;这种开发模式显得过于笨重。海思Hi3516平台提供的himm工具&#xff0c;为开发…...

[具身智能-680]:ROS2 可视化与调试工具与示例

按日常开发必用分类&#xff0c;每条可直接复制运行&#xff0c;新手也能马上上手。一、3D 可视化工具1. rviz2&#xff08;核心 3D 可视化&#xff09;功能查看&#xff1a;机器人模型、激光雷达、点云、地图、TF 坐标、导航路径、相机图像、机械臂、代价地图等。启动bash运行…...

设计师连夜删稿的真相:Onion Skin未启用导致版本错位!3分钟紧急修复+历史帧自动锚定脚本

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;设计师连夜删稿的真相&#xff1a;Onion Skin未启用导致版本错位&#xff01;3分钟紧急修复历史帧自动锚定脚本 当动画师在 Toon Boom Harmony 或 Adobe Animate 中反复导出“看似正确”的中间帧&#…...

AC鸭的迷宫按钮

题目描述AC鸭来到一个迷宫里&#xff0c;迷宫有 n 行 m 列。迷宫中有五种字符&#xff1a;A 表示 AC鸭一开始的位置。B 表示出口的位置。. 表示可以经过的空地。# 表示一开始不能经过的墙。K 表示按钮。AC鸭每一步可以向上、下、左、右四个方向移动一格&#xff0c;不能走出迷宫…...

终极解决方案:3分钟快速修复VC++运行库缺失问题,彻底告别软件启动失败

终极解决方案&#xff1a;3分钟快速修复VC运行库缺失问题&#xff0c;彻底告别软件启动失败 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 你是否经常遇到游戏或…...

告别手动拼报文!用MQTT.fx和OneNet平台快速调试你的ESP8266物联网设备

用MQTT.fx与OneNet构建高效物联网调试工作流 调试物联网设备时&#xff0c;你是否厌倦了反复修改代码、烧录固件、查看串口日志的循环&#xff1f;当ESP8266与OneNet平台通信异常时&#xff0c;传统调试方式往往让我们陷入二进制报文的泥潭。本文将介绍如何通过MQTT.fx这款图形…...