【Java从入门到放弃 之 多线程 四】

多线程 四

  • 多线程 四
    • 读写锁的使用
      • 代码演示
    • 乐观锁的使用
      • 代码演示
    • 信号量
      • 代码演示
    • 倒计时门禁
      • 代码演示
    • 循环栅栏
    • Condition详解
      • 代码案例

多线程 四

读写锁的使用

上一篇我们介绍到了可重入锁,现在我们来介绍读写锁。实际上,使用可重入锁的时候我们就可以明显感知到,其实是有优化的地方的。因为读的时候加的锁不应该跟写入的时候的锁一样。这样会降低并发效率的(因为多个线程同时读的话并不会造成问题)

代码演示

class Count {private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();private final Lock readLock = readWriteLock.readLock();private final Lock writeLock = readWriteLock.writeLock();private int a;public int add() {writeLock.lock();try {a++;}finally {writeLock.unlock();}return a;}public int get() {readLock.lock();try {return a;}finally {readLock.unlock();}}}

所以当我们面对的是改动不是很频繁,但是读取很频繁的场景的时候,实际上我们就可以考虑使用读写锁了

乐观锁的使用

前面的读写锁,已经在原有的临界资源的上,放开了多个线程同时读。但是如果写入的时候,有线程正在读的话,写的线程就必须要等待读线程完成,不然就会导致不一致。乐观锁的优化点是,在我们实际开发过程中,实际上写入是比较少的。我们写线程可以乐观不用等读线程结束。但这样肯定会有一些读写不一致的现象。 这时候就需要我们在代码里进行处理。注意乐观锁是不可重入锁。

代码演示

class Count1 {private final StampedLock stampedLock = new StampedLock();private int a;public int add() {long version = stampedLock.writeLock();try {a++;}finally {stampedLock.unlock(version);}return a;}public int get() {long tryOptimisticRead = stampedLock.tryOptimisticRead();if (!stampedLock.validate(tryOptimisticRead)) { // 看乐观锁是不是通过// 乐观锁不通过,获取悲观锁stampedLock.readLock();try {return a;}finally {stampedLock.unlockRead(tryOptimisticRead);}}return a;}}

信号量

信号量就好比,我们现实生活中,排队上厕所。一共就4个厕所。有人出来就释放厕所资源,后面的人可以获取资源,使用资源。比较简单好理解。

代码演示

class Count2 {final Semaphore semaphore = new Semaphore(5);public String get() throws InterruptedException {semaphore.acquire();try {return ""; // do something here}finally {semaphore.release();}}}

倒计时门禁

CountDownLatch类,只有倒计时的数字变成0才会放开。主要用于线程协同,要么控制同时开始,要么控制主从协作。

代码演示

public class Test19 {public static void main(String[] args) throws InterruptedException {CountDownLatch count = new CountDownLatch(2);List<Thread> threads = new ArrayList<>();for (int i = 0; i < 2; i++) {Thread thread = new Thread(new Runnable() {@Overridepublic void run() {try {Thread.sleep(2000);System.out.println(Thread.currentThread().getName());} catch (InterruptedException e) {e.printStackTrace();}finally {count.countDown();}}});thread.start();threads.add(thread);}count.await();System.out.println("main over");}
}

这段代码实现的就是主线程,会等待所有子线程执行完毕。

循环栅栏

CyclicBarrier类,相当于是一个栅栏,所有线程在到达该栅栏后都需要等待其他线程,等所有线程都到达后再一起通过,它是循环的,可以用作重复的同步。循环栅栏的功能跟倒计时门禁的功能类似,只不过它是一直循环重复的,就不给代码演示了。

Condition详解

上一篇文章中,我说到了之前我们使用synchronized 是Java语言原生支持的,所以Object有协同用的方法。 现在我们线程协同,我们应使用Condition进行协同

使用方法:

  • Condition对象必须从Lock实例的newCondition()返回。
  • Condition的await()、signal()、signalAll()方法和synchronized使用的wait()、notify()、notifyAll()可以进行类比,就不展开了
public interface Condition {void await() throws InterruptedException;void awaitUninterruptibly();long awaitNanos(long var1) throws InterruptedException;boolean await(long var1, TimeUnit var3) throws InterruptedException;boolean awaitUntil(Date var1) throws InterruptedException;void signal();void signalAll();
}

代码案例

public class Test18 {public static void main(String[] args) throws InterruptedException {FlagThread flagThread = new FlagThread();flagThread.start();Thread.sleep(100);System.out.println("change flag");flagThread.change();}
}class FlagThread extends Thread {private volatile boolean flag = false;private Lock lock = new ReentrantLock();private Condition condition = lock.newCondition();@Overridepublic void run() {try {lock.lock();try {while (!flag) {condition.await();}} finally {lock.unlock();}System.out.println("run over flag");} catch (InterruptedException e) {Thread.interrupted();}}public void change() {lock.lock();try {this.flag = true;condition.signalAll();} finally {lock.unlock();}}
}

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

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

相关文章

Go语言链接Redis数据库

1.使用go get命令安装go-redis/v8库&#xff1a; 我这里使用的vscode工具安装&#xff1a; go get github.com/go-redis/redis/v82.创建Redis客户端实例 使用以下Go代码连接到Redis服务器并执行命令&#xff1a; package mainimport ("context""fmt"&q…

Mybatis 核心配置文件

MyBatis的全局配置文件mybatis-config.xml&#xff0c;配置内容如下&#xff1a; properties&#xff08;属性&#xff09; settings&#xff08;全局配置参数&#xff09; typeAliases&#xff08;类型别名&#xff09; typeHandlers&#xff08;类型处理器&#xff09; obj…

09 —— Webpack搭建开发环境

搭建开发环境 —— 使用webpack-dev-server 启动Web服务&#xff0c;自动检测代码变化&#xff0c;有变化后会自动重新打包&#xff0c;热更新到网页&#xff08;代码变化后&#xff0c;直接替换变化的代码&#xff0c;自动更新网页&#xff0c;不用手动刷新网页&#xff09; …

TCP vs UDP:如何选择适合的网络传输协议?

在网络通信中&#xff0c;TCP&#xff08;Transmission Control Protocol&#xff09;和UDP&#xff08;User Datagram Protocol&#xff09;是两种非常重要的传输层协议。它们各有特点&#xff0c;适用于不同类型的应用场景。本文将详细探讨TCP和UDP协议的结构、优缺点及应用&…

网络安全之内网安全

下面给出了应对企业内网安全挑战的10种策略。这10种策略即是内网的防御策略&#xff0c;同时也是一个提高大型企业网络安全的策略。 1、注意内网安全与网络边界安全的不同 内网安全的威胁不同于网络边界的威胁。网络边界安全技术防范来自Internet上的攻击&#xff0c;主要是防…

7-2 扑克牌花色

作者 李祥 单位 湖北经济学院 给 52 张扑克牌面编号如下&#xff1a; 编号牌面编号牌面编号牌面编号牌面0♠A13♥A26♣A39♦A1♠214♥227♣240♦22♠315♥328♣341♦33♠416♥429♣442♦44♠517♥530♣543♦55♠618♥631♣644♦66♠719♥732♣745♦77♠820♥833♣846♦88♠9…

windows 中docker desktop 安装

前提条件&#xff1a; 安装wsl2 1. 下载 Docker Desktop 访问 Docker Desktop 官方下载页面。 https://www.docker.com/products/docker-desktop/ 根据你的操作系统架构&#xff08;一般为 Windows x86_64&#xff09;下载安装程序。 选择标准&#xff1a; AMD64 是行业…

初学 flutter 环境变量配置

一、jdk&#xff08;jdk11&#xff09; 1&#xff09;配置环境变量 新增&#xff1a;JAVA_HOMEC:\Program Files\Java\jdk-11 //你的jdk目录 在path新增&#xff1a;%JAVA_HOME%\bin2&#xff09;验证是否配置成功&#xff08;cmd运行命令&#xff09; java java -version …

Linux——进程间通信之管道

进程间通信之管道 文章目录 进程间通信之管道1. 进程间通信1.1 为什么要进行进程间的通信1.2 如何进行进程间的通信1.3 进程间通信的方式 2. 管道2.1 匿名管道2.1.1 系统调用pipe()2.1.2 使用匿名管道进行通信2.1.1 匿名管道四种情况2.1.2 匿名管道的五大特性2.1.3 进程池 2.2 …

Sigrity SPEED2000 DDR simulation模式如何生成和解读DDR仿真报告-SODIMM-Write模式

Sigrity SPEED2000 DDR simulation模式如何生成和解读DDR仿真报告-SODIMM-Write模式 Sigrity SPEED2000 DDR simulation模式如何进行DDR仿真分析操作指导-SODIMM-Write模式详细介绍了如何进行DDR Write模式的仿真分析,下面基于此仿真结果进行DDR报告的输出和解读分析 在workfl…

【机器学习chp7】SVM

参考1&#xff0c;笔记 SVM笔记.pdf 参考2&#xff1a;王木头视频 什么是SVM&#xff0c;如何理解软间隔&#xff1f;什么是合叶损失函数、铰链损失函数&#xff1f;SVM与感知机横向对比&#xff0c;挖掘机器学习本质_哔哩哔哩_bilibili 目录 一、SVM模型 二、构建决策函…

使用Electron将vue2项目打包为桌面exe安装包

目录 一、下载electron模板项目 【electron-quick-start】​ 二、打开项目&#xff0c;安装所有依赖 三、在打exe包的时候报错是因为没有&#xff0c;需要检查并安装之后重新打包&#xff1b; 四、经过这么疯狂的一波操作之后&#xff0c;就可以打包出你想要的exe安装包&am…

摄像机常见的问题及解决方法

文章目录 1)红外网络枪形摄像机白天出现模糊&#xff0c;晚上出现星芒灯2、摄像机夜晚效果调整3、网络摄像机帧率和码流调整4、码流对图像质量的影响 如果你在安装的过程中,出现了以下的问题,请对照下列描述解决你的问题&#xff1a; 1)红外网络枪形摄像机白天出现模糊&#xf…

决策树分类算法【sklearn/决策树分裂指标/鸢尾花分类实战】

决策树分类算法 1. 什么是决策树&#xff1f;2. DecisionTreeClassifier的使用&#xff08;sklearn&#xff09;2.1 算例介绍2.2 构建决策树并实现可视化 3. 决策树分裂指标3.1 信息熵&#xff08;ID3&#xff09;3.2 信息增益3.3 基尼指数&#xff08;CART&#xff09; 4. 代码…

001 数字逻辑概论

1.1 数字信号与数字电路 目标1&#xff1a;what is 数字信号与数字电路 1.1.1.数字技术的发展及其应用 &#xff08;1&#xff09;发展&#xff1a; 发展过程特点: 以电子器件的发展为基础&#xff0c;如下图 电子管时代&#xff1a; 电子管&#xff1b;电子管体积大、重量…

Rust中Tracing 应用指南

欢迎来到这篇全面的Rust跟踪入门指南。Rust 的tracing是一个用于应用程序级别的诊断和调试的库。它提供了一种结构化的、异步感知的方式来记录日志和跟踪事件。与传统的日志记录相比&#xff0c;tracing能够更好地处理复杂的异步系统和分布式系统中的事件跟踪&#xff0c;帮助开…

C语言——break、continue、goto

目录 一、break 二、continue 1、在while循环中 2、在for循环中 三、go to 一、break 作用是终止循环&#xff0c;在循环内遇到break直接就跳出循环。 注&#xff1a; 一个break语句只能跳出一层循环。 代码演示&#xff1a; #include<stdio.h>void test01() {for (…

SSM全家桶 1.Maven

或许总要彻彻底底地绝望一次 才能重新再活一次 —— 24.11.20 maven在如今的idea中已经实现自动配置&#xff0c;不需要我们手动下载 一、Maven的简介和快速入门 Maven 是一款为 Java 项目构建管理、依赖管理的工具(软件)&#xff0c;使用 Maven 可以自动化构建测试、打包和发…

Oracle SQL*Plus中的SET VERIFY

在 Oracle SQL*Plus 中&#xff0c;SET VERIFY ON 和 SET VERIFY OFF 是两个用于控制命令执行前后显示变量值的命令。这些命令主要用于调试和验证 SQL 脚本中的变量替换情况。 一、参数说明 1.1 SET VERIFY ON 作用&#xff1a;启用变量替换的验证功能。当启用时&#xff0c;S…

双因子认证:统一运维平台安全管理策略

01双因子认证概述 双因子认证&#xff08;Two-Factor Authentication&#xff0c;简称2FA&#xff09;是一种身份验证机制&#xff0c;它要求用户提供两种不同类型的证据来证明自己的身份。这通常包括用户所知道的&#xff08;如密码&#xff09;、用户所拥有的&#xff08;如…