java并发体系-锁

ReentrantLock 

     ReentrantLock是Java并发编程中的一种锁机制。它的基本流程如下:

  1. 创建ReentrantLock对象。
  2. 在需要加锁的代码块前调用lock()方法,该方法会尝试获取锁,如果锁已被其他线程占用,则当前线程会被阻塞。
  3. 执行需要加锁的代码。
  4. 在加锁代码块的finally语句块中调用unlock()方法来释放锁。

ReentrantLock的特点和用法如下:

  1. 可重入性:ReentrantLock是可重入锁,即同一个线程可以重复获取该锁,而不会发生死锁。这是通过维护一个持有锁的线程的引用计数来实现的。
  2. 公平性:ReentrantLock可以指定是公平锁还是非公平锁,默认情况下是非公平锁。公平锁是按照线程申请锁的顺序来分配锁,而非公平锁则是随机分配锁,可能会导致某些线程饥饿。
  3. 条件变量:ReentrantLock提供了Condition接口的实现,可以通过该接口实现对线程的等待和唤醒机制,更灵活地控制线程的同步。
  4. 可中断:ReentrantLock提供了lockInterruptibly()方法,如果当前线程还没有获取到锁,但是被其他线程中断,可以通过该方法响应中断。

以下是一个使用ReentrantLock的Java代码示例:

import java.util.concurrent.locks.ReentrantLock;public class ReentrantLockExample {private static ReentrantLock lock = new ReentrantLock();public static void main(String[] args) {// 创建并启动多个线程for (int i = 0; i < 5; i++) {Thread thread = new Thread(new MyThread());thread.start();}}static class MyThread implements Runnable {@Overridepublic void run() {try {// 加锁lock.lock();// 执行需要加锁的代码System.out.println("Thread " + Thread.currentThread().getId() + " is running");Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();} finally {// 释放锁lock.unlock();}}}
}

     在上述示例中,我们创建了一个ReentrantLock对象,并在MyThread的run()方法中加锁、执行代码、释放锁。在main方法中,我们创建并启动了5个线程,它们会依次获取锁并执行代码。由于ReentrantLock是可重入锁,同一个线程可以多次获取锁,所以每个线程都可以成功地执行代码块。

ReentrantReadWriteLock

     ReentrantReadWriteLock是Java并发编程中的一个锁机制,它是一种读写锁,允许多个线程同时读共享资源,但只能有一个线程写资源。ReentrantReadWriteLock在实现上通过两个锁来实现,一个是读锁(共享锁),一个是写锁(独占锁)。

基本流程如下:

  1. 多个线程可以同时获取读锁,读锁之间不互斥,可以并发执行。
  2. 获取写锁的线程会阻塞其他线程的读锁和写锁,只有释放写锁后才允许其他线程获取读写锁。

ReentrantReadWriteLock的特点和用法:

  1. 公平性:可以选择公平模式或非公平模式,默认是非公平模式。在非公平模式下,允许锁被后来的线程插队,以提高吞吐量;在公平模式下,锁会按照请求的顺序分配给线程,保证公平性。
  2. 重入性:与ReentrantLock一样,ReentrantReadWriteLock可以重入,同一个线程可以多次获取读锁或写锁。
  3. 锁降级:一个线程拥有写锁的时候,可以先获取读锁,然后再释放写锁,这样就实现了锁的降级。
  4. 锁升级:读锁不能升级为写锁,因为会有死锁的风险。

下面是一个简单的示例代码,展示了ReentrantReadWriteLock的用法:

import java.util.concurrent.locks.ReentrantReadWriteLock;public class MyReadWriteLock {private int value = 0;private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();public int getValue() {lock.readLock().lock(); // 获取读锁try {return value;} finally {lock.readLock().unlock(); // 释放读锁}}public void increment() {lock.writeLock().lock(); // 获取写锁try {value++;} finally {lock.writeLock().unlock(); // 释放写锁}}
}

    在上面的示例中,MyReadWriteLock类包含一个value变量和一个ReentrantReadWriteLock对象。getValue()方法获取读锁,读取value的值并返回。increment()方法获取写锁,将value加1。通过使用读写锁,多个线程可以同时读取value的值,但只有一个线程可以写入value的值。

Condition

     Condition是Java并发编程中的一种同步机制,它可以用于实现线程之间的等待和通知。

基本流程:

  1. 创建一个Lock对象,通过Lock对象的newCondition()方法创建一个Condition对象。
  2. 通过Lock对象的lock()方法获取锁。
  3. 在某个线程中,通过Condition对象的await()方法使线程等待,同时释放锁。
  4. 在另一个线程中,通过Condition对象的signal()或signalAll()方法进行通知。
  5. 在第一个线程中,通过Condition对象的await()方法再次获取锁并继续执行。

特点和用法:

  1. 可以与Lock对象配合使用,对某个共享资源进行互斥访问和条件等待。
  2. 可以精确地控制线程的等待和通知。

示例代码:

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 condition = lock.newCondition();private boolean flag = false;public void waitForFlag() throws InterruptedException {lock.lock();try {while (!flag) {condition.await(); // 线程等待并释放锁}} finally {lock.unlock();}System.out.println("Flag is true, continue executing.");}public void setFlag() {lock.lock();try {flag = true;condition.signalAll(); // 发送通知并唤醒等待线程} finally {lock.unlock();}}public static void main(String[] args) throws InterruptedException {final ConditionExample example = new ConditionExample();Thread waitingThread = new Thread(() -> {try {example.waitForFlag();} catch (InterruptedException e) {e.printStackTrace();}});Thread settingThread = new Thread(() -> {try {Thread.sleep(2000); // 模拟执行耗时操作example.setFlag();} catch (InterruptedException e) {e.printStackTrace();}});waitingThread.start();settingThread.start();waitingThread.join();settingThread.join();}
}

     在上述示例中,有两个线程,一个线程等待flag变量为true,另一个线程在某一时刻将flag设置为true。通过Condition对象的await()方法使等待线程进入等待状态,并释放锁,直到另一个线程通过Condition对象的signalAll()方法发送通知并唤醒等待线程,等待线程再次获取锁并继续执行。

总结 

     Java并发体系中的锁是用来管理多个线程对共享资源的访问的工具。锁的使用可以确保多个线程之间的同步和互斥,从而避免竞态条件和数据的不一致性。

Java中的锁可以分为两大类:内置锁和显式锁。

  1. 内置锁:

    • synchronized关键字:synchronized是Java中最基本的内置锁机制。它可以修饰方法或代码块,一次只允许一个线程访问被修饰的代码块或方法。当一个线程获得锁时,其他线程必须等待锁释放才能继续执行。
    • 锁对象:synchronized还可以用于指定一个对象作为锁。当一个线程获得该对象的锁时,其他线程对该对象的访问将被阻塞。这种方式可以实现更细粒度的锁控制。
  2. 显式锁:

    • ReentrantLock类:ReentrantLock是Java提供的显式锁的实现类。它提供了与synchronized类似的功能,但提供了更灵活的锁控制。通过lock()方法获取锁,通过unlock()方法释放锁。ReentrantLock还提供了一些其他功能,如可中断锁、公平锁等。
    • Condition接口:Condition接口是与显式锁ReentrantLock配合使用的重要组件。它可以让线程在等待某个条件满足时暂时释放锁,从而避免了线程一直占用锁资源而无法执行其他任务。

           锁的选择应根据具体的需求和场景来决定。synchronized是最简单和常用的锁机制,适用于大部分情况。ReentrantLock提供了更多的灵活性和高级功能,例如可中断锁、公平锁等,但使用起来相对复杂一些。在多个线程需要等待某个条件满足时,使用Condition接口可以更好地控制线程的等待和唤醒。

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

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

相关文章

redis架构知识点

Redis 在规模如下&#xff1a; 机器内存总量约70TB&#xff0c;实际使用内存约40TB&#xff1b;平均每秒处理约1500万次请求&#xff0c;峰值每秒约2000万次请求&#xff1b;每天处理约1万亿余次请求&#xff1b;单集群每秒处理最高每秒约400万次请求&#xff1b;集群实例与单机…

3 突破编程_前端_SVG(rect 矩形)

1 rect 元素的基本属性和用法 在SVG中&#xff0c;<rect> 元素用于创建矩形。 <rect> 元素有一些基本的属性&#xff0c;可以用来定义矩形的形状、位置、颜色等。以下是这些属性的详细解释&#xff1a; x 和 y &#xff1a;这两个属性定义矩形左上角的位置。 x …

[dvwa] sql injection(Blind)

blind 0x01 low 1’ and length(version()) 6 # syntax: substr(string , from<start from 1>, cut length) 1’ and substr(version(),1,1) ‘5’ # 1’ and substr(version(),2,1) ‘.’ # 1’ and substr(version(),3,1) ‘7’ # 1’ and substr(version(),4,…

leetcode 322

leetcode 322 题目 例子 思路 记忆化搜索&#xff0c;使用数组&#xff0c;记录val的最少硬币数量&#xff1b; 递归加bfs; 代码实现 #include <vector> #include <climits> // For INT_MAX #include <algorithm> // For minclass Solution { public:int…

C#下Httpclient post请求获取令牌

1.postman测试ok 2.C#代码 public static async Task<string> testGetToken(string URL, string param){string responseBody "eee";//using (var clientHandler new HttpClientHandler()){ var handler new HttpClientHandler();handler.ServerCertificat…

响应实践!赛宁网安亮相第二届全国先进技术成果转化大会

4月8日&#xff0c;第二届全国先进技术成果转化大会&#xff08;以下简称“大会”&#xff09;在苏州隆重举行。大会由江苏省国防科学技术工业办公室、苏州市人民政府、先进技术成果长三角转化中心主办。赛宁网安作为全球一流数字孪生靶场服务商&#xff0c;携数字孪生靶场、网…

软件测试面试准备—综合面

技术面试过了之后&#xff0c;HR约综合面&#xff0c;其实面之前我不太确定是不是HR面&#xff0c;以及会有哪些人&#xff0c;所以还是整理了下问题。有些问题附上答案&#xff0c;有些问题需要结合自己的工作场景来发挥。我参与的这家公司的综合面是HR来面的&#xff0c;其实…

python学习——re库的常用函数

参考资料&#xff1a;python网络爬虫技术与应用【邓维】 1、match() 从字符串头部开始匹配字符。 import re content"The123456ismyonephonenumber." # 字符串长度 print(len(content)) # 使用match匹配&#xff0c;第一个参数为正则表达式&#xff0c;第二个参数…

未来驾驶的革命:自动驾驶技术与智能交通系统的崛起

虽然自动驾驶技术和智能交通系统的开发似乎是资本密集型且技术要求高的领域&#xff0c;主要由大型企业主导&#xff0c;但普通创业者仍有机会从多个角度切入这一领域。以下是一些创业机会的思路&#xff1a; 1. 软件解决方案和应用开发 数据分析和处理工具 在自动驾驶技术领域…

element-ui的按需引入报错解决:MoudleBuildFailed,完整引入和按需引入

官网&#xff1a; Element - The worlds most popular Vue UI framework 1.完整引入 &#xff08;1&#xff09;下载&#xff1a; npm i element-ui -S &#xff08;2&#xff09;引入&#xff1a; 在 main.js 中写入以下内容&#xff1a; import Vue from vue; impor…

MLT媒体程序框架02:源码剖析

以MLT自带的Melt命令行工具源码为例 去掉一些不重要的代码 melt.c int main(int argc, char **argv) {int i;mlt_consumer consumer NULL;FILE *store NULL;char *name NULL;mlt_profile profile NULL;int is_progress 0;int is_silent 0;int is_abort 0;int is_getc …

javascript中创建变量的方式 与 var和let有什么区别

一、创建变量的7种方式&#xff1a; 1、var 2、function 创建变量&#xff08;函数名是一个变量 3、let 4、const 创建常量 5、import 基于es6 的模块规范导出需要的信息 6、class 基于 es6 创建的类 7、Symbol 创建唯一值 二…

Linux进阶篇:centos7扩展root分区:LVM应用案例

centos7扩展root分区&#xff1a;LVM应用案例 当服务器根分区或者是root分区存储空间快用完的时候&#xff0c;并且重要的数据都在root分区下&#xff0c;当如何应对&#xff0c;没关系坐好&#xff0c;分分钟解决它&#xff0c;我们可以进行分区扩容。 一 添加一块新的硬盘 …

谈谈系列之移动时代,我的产品技术观

其实一直想着写这篇文章&#xff0c;但是缺乏灵感&#xff0c;下笔犯难。信息时代发展速度快到令人目不暇接&#xff0c;从最开始的个人PC&#xff0c;到拨号上网&#xff0c;再到光纤入户&#xff0c;再到现在4G/5G移动互联网&#xff0c;一晃也不过短短三四十年。程序主流语言…

java 读取zip文件的两种方式

以下是使用Java读取zip文件的两种实现方法&#xff1a; 方法1&#xff1a;使用java.util.zip.ZipInputStream类 import java.io.FileInputStream; import java.io.InputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream;public class ZipReader …

某中小型网游公司绩效管理诊断项目成功案例纪实

【客户行业】 网游行业 【问题类型】 绩效管理 【客户背景】 某中小型网游科技发展有限公司成立于2006年,是一家专业的网页游戏研发、互联网应用、手机游戏开发于一体的高新技术科技企业,位于北京市昌平区。公司自成立以来,一直稳步发展,到目前为止,员工人数约150人。近…

鸿蒙应用开发之图案密码锁组件

前面学习了导航组件,现在来学习另一个密码设置和验证组件,这种组件比较常用。因为当用触屏手机之后,屏幕上就可以滑动操作,比普通PC电脑要多一些功能了。早前的密码都是输入数字,没有滑动输入九宫格的密码。 大体如下面的界面: 采用这种密码,一般情况下是不用记住数字,…

pytest详解(一)

目录 前言安装检验 编写测试文件一个简单完整的pytest的组成结构 pytest运行用例时携带的参数&#xff08;常用&#xff09;pytest的用例命名规则pytest的常用运行方式pytest指定运行用例指定运行一个文件夹中的用例指定运行一个文件夹中的一个文件中的用例指定运行一个文件夹中…

汇编——SSE打包整数

SSE也可以进行整数向量的加法&#xff0c;示例如下&#xff1a; ;sse_integer.asm extern printfsection .datadummy db 13 align 16pdivector1 dd 1dd 2dd 3dd 4pdivector2 dd 5dd 6dd 7dd 8fmt1 db "Packed Integer Vector 1: %d, %d, %d, %d",…

【鹅厂摸鱼日记(二)】(生活篇)初到深圳的人情冷暖

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:重生之我在鹅厂摸鱼⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习更多知识   &#x1f51d;&#x1f51d; 摸鱼日记 1. 前言2. 鹅厂的人文关怀…