java多线程-扩展知识三:乐观锁与悲观锁

1、悲观锁

        悲观锁有点像是一位比较悲观(也可以说是未雨绸缪)的人,总是会假设最坏的情况,避免出现问题。

        悲观锁总是假设最坏的情况,认为共享资源每次被访问的时候就会出现问题(比如共享数据被修改),所以每次在获取资源操作的时候都会上锁,这样其他线程想拿到这个资源就会阻塞直到锁被上一个持有者释放。也就是说,共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程。
        Java 中synchronizedReentrantLock等独占锁就是悲观锁思想的实现。 

public void performSynchronisedTask() {
    synchronized (this) {
        // 需要同步的操作
    }
}

private Lock lock = new ReentrantLock();
lock.lock();
try {
   // 需要同步的操作
} finally {
    lock.unlock();
}

2、乐观锁

        乐观锁有点像是一位比较乐观的人,总是会假设最好的情况,在要出现问题之前快速解决问题

         乐观锁总是假设最好的情况,认为共享资源每次被访问的时候不会出现问题,线程可以不停地执行,无需加锁也无需等待,只是在提交修改的时候去验证对应的资源(也就是数据)是否被其它线程修改了(具体方法可以使用版本号机制或 CAS 算法)。

        Java 中java.util.concurrent.atomic包下面的原子变量类(比如AtomicInteger、LongAdder)就是使用了乐观锁的一种实现方式CAS实现的。 

// LongAdder 在高并发场景下会比 AtomicInteger 和 AtomicLong 的性能更好
// 代价就是会消耗更多的内存空间(空间换时间)
LongAdder longAdder = new LongAdder();
// 自增
longAdder.increment();
// 获取结果
longAdder.sum();

3、使用选择

  • 悲观锁通常多用于写比较多的情况下(多写场景,竞争激烈),这样可以避免频繁失败和重试影响性能,悲观锁的开销是固定的。不过,如果乐观锁解决了频繁失败和重试这个问题的话(比如LongAdder),也是可以考虑使用乐观锁的,要视实际情况而定。
  • 乐观锁通常多于写比较少的情况下(多读场景,竞争较少),这样可以避免频繁加锁影响性能。不过,乐观锁主要针对的对象是单个共享变量(参考java.util.concurrent.atomic包下面的原子变量类)。 

 4、乐观锁实现

        Java中的乐观锁主要有两种实现方式:CAS(Compare and Swap)和版本控制

4.1、CAS

        CAS是实现乐观锁的核心算法,它通过比较内存中的值是否和预期的值相等来判断是否存在冲突。如果存在,则返回失败;如果不存在,则执行更新操作。

        

  • CAS操作包括三个操作数:内存位置(V)、预期原值(A)和新值(B)。
  • 当执行CAS操作时,只有当V的值等于A时,才会将V的值更新为B,否则不做任何操作。
  • CAS操作是原子性的,也就是说在同一时刻只能有一个线程执行CAS操作,因此CAS机制保证了数据的一致性。

 Java中提供了AtomicInteger、AtomicLong、AtomicReference等原子类来支持CAS操作。

public class Counter {
    private AtomicInteger value = new AtomicInteger(0);

    public void increment() {
        int expect;
        int update;

        do {
            expect = value.get();
            update = expect + 1;
        } while (!value.compareAndSet(expect, update));
    }
}

4.2、版本控制

        每当一个线程要修改数据时,都会先读取当前的版本号或时间戳,并将其保存下来。线程完成修改后,会再次读取当前的版本号或时间戳,如果发现已经变化,则说明有其他线程对数据进行了修改,此时需要回滚并重试。

public class Counter {
    private int value = 0;
    private int version = 0;

    public void increment() {
        int currentVersion;
        int currentValue;

        do {
            currentVersion = version;
            currentValue = value;
            currentValue++;
        } while (currentVersion != version);

        value = currentValue;
        version = currentVersion + 1;
    }
}

5、补充

5.1、ConcurrentHashMap

        ConcurrentHashMap是Java中的一个线程安全的哈希表实现,它使用分离锁(Segment)来保证线程安全。每个Segment都是一个独立的哈希表,每个操作只锁定相关的Segment,因此可以支持更高的并发性。

        ConcurrentHashMap使用了一种基于CAS的技术来实现乐观锁,它通过比较当前的value和预期的value是否相等来判断是否存在冲突。如果存在,则返回失败;如果不存在,则执行更新操作。

5.2、LongAdder

        在 JDK1.8 中,Java 提供了一个新的原子类 LongAdder。LongAdder 在高并发场景下会比 AtomicInteger 和 AtomicLong 的性能更好,代价就是会消耗更多的内存空间

LongAdder 的原理就是降低操作共享变量的并发数,也就是将对单一共享变量的操作压力分散到多个变量值上,将竞争的每个写线程的 value 值分散到一个数组中,不同线程会命中到数组的不同槽中,各个线程只对自己槽中的 value 值进行 CAS 操作,最后在读取值的时候会将原子操作的共享变量与各个分散在数组的 value 值相加,返回一个近似准确的数值。

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

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

相关文章

Windows系统搭建Appium 2 和 Appium Inspector 环境

前言 自 2022 年 1 月 1 日起,Appium 核心团队不再维护 Appium 1.x。官方支持的平台驱动程序的所有最新版本均不兼容 Appium 1.x,需要 Appium 2 才能运行。 Appium 2是一个自动化移动应用程序的开源工具,它带来了以下重要改进:  …

软件测评中心▏软件集成测试和功能测试之间的区别和联系简析

软件集成测试是在软件开发周期的后期阶段进行的测试活动,旨在验证系统各个组件之间的接口和交互是否正常工作。而功能测试是一种验证软件系统是否按照需求规格说明书所规定的功能进行正确实现的测试。接下来,我们来分别探讨一下软件集成测试和功能测试有…

hadoop安装

简介 Hadoop是一个开源的分布式存储和计算框架,最初由Apache软件基金会开发。它的发展背景可以追溯到Google的MapReduce和Google File System(GFS)的论文,这两篇论文启发了Hadoop的设计。Hadoop的主要应用场景包括大数据存…

rabbitmq-server-3.11.10.exe

rabbitmq需要erlang环境 otp_win64_25.1.exe erlang-CSDN博客 https://www.rabbitmq.com/download.htmlhttps://www.rabbitmq.com/install-windows.htmlhttps://github.com/rabbitmq/rabbitmq-server/releases/download/v3.11.10/rabbitmq-server-3.11.10.exe C:\Users\Admi…

使用MechanicalSoup库的爬虫程序

1. 首先,我们需要导入MechanicalSoup库和requests库,这两个库都是Python中爬虫常用的库。 2. 接着,我们要设置一个代理服务器,使用proxy_host和proxy_port参数来指定。 3. 使用requests.get方法来获取网页的HTML代码。 4. 使用Bea…

添加通信作者标记、共同作者标记

1 添加通信作者的小信封 添加包,2个小信息长得不太一样选一个用 % \usepackage[misc]{ifsym} \usepackage{marvosym} % 通信小信封 然后在名字后面添加\Letter Ming Li\Letter\textsuperscript{\rm 1}\

WordPress 粘贴图片上传插件

找了很久,发现一款不错的插件,允许我们直接粘贴图片文件并且上传到媒体库。以前的插件上传后媒体库不会显示,这个要显示。 启用后编辑器会有一个图标,如果开启,那么久可以截图后直接粘贴了。 学习资料源代码&#xf…

硬核实力,闪耀羊城!第23届广州车展完美收官,大运乘用车尽显品牌魅力

11月26日,第23届广州国际车展在广州圆满闭幕。作为各大车展的老朋友,本届广交会大运乘用车携旗下潮玩纯电越野小钢炮悦虎及大7座智能豪华纯电MPV远志M1两大明星车型闪耀全场,再次揽收空前关注。 当下以85、90、00后为主的年轻群体看中新能源汽…

去水印软件有哪些?亲测四款好用去水印神器

去水印软件有哪些?随着图片的普及和应用范围不断扩大,我们有时需要对图片进行编辑或修改。然而,有些图片可能会带有水印,这会降低图片的美观度和应用效果。作为一名自媒体打工人,经过多番对比,整理了四款好…

计算机视觉的应用20-图像生成模型(Stable Diffusion)的原理详解与相关项目介绍

大家好,我是微学AI,今天给大家介绍一下计算机视觉的应用20-图像生成模型:Stable Diffusion模型的原理详解与相关项目介绍。大家知道现在各个平台发的各种漂亮的女生,这些漂亮的图片是怎么生成的吗,其实它们底层原理就是…

JoySSL证书从申请到安装

为了保护网站和用户数据的安全,使用SSL证书是至关重要的一步。JoySSL是一种可靠的SSL证书提供商,它提供了简单易用的证书申请和安装流程。本文将详细介绍如何从申请到安装JoySSL证书的步骤。 一、申请JoySSL证书 1,访问JoySSL官方网站&#…

1120:最值交换

题目描述 有一个长度为n的整数序列。请写一个程序,先把序列中的最小值与第一个数交换,再把最大值与最后一个数交换。输出转换好的序列。 分别编写两个函数MinIndex()和MaxIndex()来计算最小值下标和最大值下标。 int MinIndex(int a[], int n); //函数返…

医院室内导航解决方案:智慧医疗的重要组成部分

医院作为人们生活中不可或缺的一部分,面临着巨大的挑战。每天都有大量的患者前来就医,而医院内部的复杂结构和科室众多,常常让患者感到困惑和迷失。为了解决这个问题,医院室内导航解决方案应运而生,以其创新的技术和卓…

如何使用录屏软件在电脑录制PDF文件

我有一个PDF文件,想用录屏软件将它录制下来并添加上详细的注释,然后发给客户看,请问应该如何录制呢?有没有推荐的录屏软件呢? 不用担心,本文将会详细的为您讲解如何使用录屏软件在电脑端录制PDF文件&#…

C# 将bin文件转成hex文件

背景 由于项目应用(服务器-APP-下位机)中, 1)服务器限制只能上传hex文件 2)APP中通过应用读取的数据为bin文件 所以需要APP中将bin文件转成hex文件,,正好做个bin转hex的功能 注:应用读取的bin文件实际是MC…

selenium+python

selenium 八大查找元素 from selenium import webdriver from selenium.webdriver.common.by import By# 创建一个 WebDriver 实例 driver webdriver.Chrome()# 打开网页 driver.get("https://www.baidu.com/")# 使用 find_element 方法查找元素 element driver.…

vue3-在自定义hooks使用useRouter 报错问题

文章目录 前言一、报错分析报错的Vue warn截图:查看文档 二、那么在hook要怎么引入路由呢? 前言 记录在vue3项目中,hook使用useRouter 报错问题 一、报错分析 报错的Vue warn截图: 警告 inject() can only be used inside setup…

vue+less+style-resources-loader 配置全局颜色变量

全局统一样式后,可配置vue.config.js实现全局颜色变量,方便在编写时使用统一风格的色彩 一、新建global.less 二、下载安装style-resources-loader npm i style-resources-loader --save-dev三、在vue.config.js中进行配置 module.exports {pluginOpt…

手把手教你在AutoML上部署Qwen-7B-hat Transformers 部署调用

手把手带你在AutoDL上部署Qwen-7B-hat Transformers 调用 项目地址:https://github.com/datawhalechina/self-llm.git 如果大家有其他模型想要部署教程,可以来仓库提交issue哦~ 也可以自己提交PR! 如果觉得仓库不错的话欢迎star!&…

linux系统下的nginx服务安装

一. 环境 在安装nginx前,需要提前配置的环境包括 pcre:rewrite正则相关pcre:URL重写软件,实现伪静态\URL跳转等、SEO优化。 openssl:https加密访问用它 zlib:提供数据压缩用1.安装pcre 1.1 检查版本 执行&#xff…