JavaWeb——锁策略, cas和synchronized优化过程

news2024/12/23 15:58:06

目录

一、锁策略

1、悲观锁和乐观锁

2、轻量级锁和重量级锁

3、自旋锁和挂起等待锁

4、互斥锁和读写锁

5、可重入锁和不可重入锁

6、公平锁和非公平锁

二、cas和synchronized 优化过程

1、CAS(compare and swap)

(1)、原子类

(2)、自旋锁

2、synchronized实现策略:

(1)、锁升级


一、锁策略

1、悲观锁和乐观锁

乐观锁和悲观锁不是具体类型的锁而是指两种不同的对待加锁的态度,这两个锁面对锁冲突的态度是相反的。

  • 乐观锁:认为不存在很多的并发操作,因此不需要加锁。
  • 悲观锁:认为存在很多并发操作,因此需要加锁。

2、轻量级锁和重量级锁

重量级锁和轻量级锁是通过结果去看待加锁解锁的过程开销。做的工作多消耗资源多,做的工作少消耗资源少。因此我们会认为乐观锁是轻量级锁,悲观锁是重量级锁。

  • 重量级锁:是进入内核态的加锁逻辑,资源开销较大。
  • 轻量级锁:是纯用户态的加锁逻辑,资源开销较小。  

3、自旋锁和挂起等待锁

  • 自旋锁:是一种轻量级锁,自旋锁类是一直反复查看当前锁是否就绪,CPU不停空转会消耗大量地CPU。
  • 挂起等待锁:是一种重量级锁,该锁不会像自旋锁一样一直查看锁状态而是先去做别的事情,过一会再来看当前锁是否就绪。

4、互斥锁和读写锁

  • 互斥锁当两个线程竞争同一把锁时会产生锁冲突进而阻塞等待。
  • 读写锁:根据代码实际的逻辑进行加锁,有读锁和写锁两种锁。读锁和读锁之间不会产生锁竞争;读锁和写锁之间会产生锁竞争;写锁和写锁之间,会产生锁竞争。如果代码中读的场景多写的场景少时,读写锁相比于互斥锁优化了效率、减少了不必要的锁竞争。

5、可重入锁和不可重入锁

  • 不可重入锁:是指同一个线程对同一把锁连续加锁两次,产生了死锁。
  • 可重入锁:是指同一个线程在外层方法获取锁,进入内层方法会自动获取锁。

注ReentrantLock和Synchronized都是可重入锁。

6、公平锁和非公平锁

公平是指遵循先来后到的原则的,因此遵守先来后到就是公平锁,不遵守先来后到的就是非公平锁

例:t1,t2,t3三个线程竞争同一把锁,谁先来的谁就拿到锁的情况叫公平锁。如果三个线程随机一个拿到锁,后来的线程可能会先拿到锁的情况叫非公平锁。

  • 公平锁:指多个线程按照申请锁的顺序来获取锁。
  • 非公平锁:指多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取锁。

注:操作系统默认的锁的调度是非公平的。系统对于线程的调度是随机的,自带的synchronized这个锁是非公平的。想要实现公平锁需要在synchronized的基础上,加个队列来记录这些加锁线程的顺序。

二、cas和synchronized 优化过程

1、CAS(compare and swap)

寄存器A的值和内存K的值进行对比,如果值相同就把寄存器B的值和内存K的值进行交换

//伪代码
boolean CAS(address,exceptValue,swapValue){
    if(&address==exceptedValue{
        &address=swapValue;
        return true;
    }
    return false;
}

注:CAS操作是一条CPU指令(不必加锁就能够保证线程安全)并非是上述这段代码,这一条指令就能完成上述这段代码的功能。

(1)、原子类

实现原子类,标准库里提供了AtomInteger类,该类可以保证++--时的线程安全

class AtomicInteger{
    private int value;

    public int getAndIncrement(){
        int oldValue=value;
        while(CAS(value,oldValue,oldValue+1)!=true){
            oldValue=vlaue;
        }
        return oldValue;
    }
}

oldValue可以被视为寄存器,如果发现value和oldValue的值相同,此时就把oldValue+1设置到value中,相当于++,然后CAS返回true,循环结束。反之如果value和oldValue不相同,CAS什么都不做并返回false,进入循环,重新设置oldValue的值。

即:此处的CAS就是在确认当前的value是否发生过改变,如果没变过才能自增,如果变过了就先更新再自增。

例: 

之前的线程不安全是因为一个线程不能及时的感知另一个线程对内存的修改。

如:t2在自增时,先读后自增。此时在自增之前t1已经自增过了,t2是在1的基础上自增的,就出现了问题。

使用CAS之后,t2在自增前会先检查寄存器的值和内存的值是否一致

(2)、自旋锁

反复检查当前的锁状态,看锁是否解开。通过CAS看当前锁是否被某个线程持有,如果这个锁已经被别的线程持有,那么就自选等待。如果这个锁没有被别的线程持有,那么就把owner设为当前尝试加锁的线程

public class SpinLock{
    private Thread owner=null;
    public void lock(){
        while(!CAS(this.owner,null,Thread.currentThread()){
            
        }
    }
    public void unlock(){
        this.owner=null;
    }
}

如果当前owner是null,比较就成功,就把当前线程的引用设置到owner中,加锁完成循环结束。比较不成功意味着owner非空,锁已经有线程持有了。此时CAS就什么也不做直接返回false,循环继续进行,此时这个循环不停尝试询问锁是否释放。

好处:一旦锁释放就能立即获取锁。

坏处:消耗大量CPU资源。 

乐观锁一般情况下锁冲突概率低,实现成自旋锁比较合适。

注:CAS的关键是对比内存和寄存器的值是否相同,但这对于aba问题会有一定概率出问题。

如何解决aba问题呢?aba问题的关键是值会反复横跳

  • 可以通过约定数据只能单方向变化(只能增加或减小)
  • 也可以通过引入另一个版本号变量,约定版本号只能增加,每次修改都会增加一个版本号。而每次CAS对比时,就不是对比数值本身,而是对比版本号。

2、synchronized实现策略:

(1)、锁升级

偏向锁:

只是先让线程针对锁有一个标记。如果整个代码执行过程中都没遇到别的线程竞争这个锁,此时就不用真的加锁了。但要是有别的线程尝试来竞争这个锁,此时偏向锁就立即升级成真的锁(轻量级锁),此时别的锁只能等待。既保证了效率,又保证了线程安全。

自旋锁:

速度快但是消耗大量cpu。自旋时cpu快速空转,如果当前锁竞争激烈,多个线程都在自旋,cpu的消耗就非常大。既然如此,就升级成重量级锁,在内核中进行阻塞等待(意味着线程要暂时放弃cpu,由内核进行后续调度)

注:运行时jvm做出的优化手段,主流的jvm实现只能升级不能降级。

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

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

相关文章

企业网站架构部署与优化

系列文章目录 文章目录系列文章目录一、LAMP概述与简介1.LAMP2.各组件的主要作用如下:二、1.编译安装Apache http服务2.编译安装 Mysql 服务3.编译安装 PHP 解析环境总结一、LAMP概述与简介 1.LAMP LAMP架构是目前成熟的企业网站应用模式之一,指的是协…

如何高效建立知识库?

建立知识库是为了更好地管理和传承知识,提高团队的效率和成果。在建立知识库的过程中,需要注意一些关键点,以确保知识库的高效性和可持续性。本文将介绍如何高效建立知识库以及需要注意的事项。 一、建立知识库的步骤 1.明确知识库的目的和…

SpringBoot 默认数据库连接池 HikariCP

目录 引言 1、问题描述 2、SpringBoot默认的数据库连接池 3、HikariCP是什么 4、测试依赖 5、配置文件 5.1、数据库连接参数 5.2、连接池数据基本参数 5.3、连接检查参数 5.4、事务相关参数 5.5、JMX参数 6、HikariCP源码浅析 6.1、HikariConfig--连接池配置的加载…

Observability:使用 OpenTelemetry 和 Elastic 监控 OpenAI API 和 GPT 模型

作者:David Hope ChatGPT 现在很火,它打破了互联网。 作为 ChatGPT 的狂热用户和 ChatGPT 应用程序的开发者,我对这项技术的可能性感到无比兴奋。 我看到的情况是,基于 ChatGPT 的解决方案将呈指数级增长,人们将需要监…

Shiro概述

文章目录1.权限的管理1.1 什么是权限管理1.2 什么是身份认证1.3 什么是授权2.Shiro概述2.1 什么是Shiro2.2 Shiro 与 SpringSecurity 的对比2.3 基本功能3.shiro的核心架构4.shiro中的认证4.1 认证4.2 shiro中认证的关键对象4.3 身份认证流程4.4.登录认证实例4.5 自定义Realm5.…

Python标记数组的连通域

文章目录连通域标记structure参数操作连通域定位连通域连通域标记 通过label函数,可以对数组中的连通区域进行标注,效果如下 from scipy.ndimage import label import numpy as np a np.array([[0,0,1,1,0,0],[0,0,0,1,0,0],[1,1,0,0,1,0],[0,0,0,1,0…

虚拟机里安装ubuntu-23.04-beta-desktop-amd64,开启SSH(换源、备份),配置中文以及中文输入法

一、下载 官网 清华镜像站(推荐) 二、配置虚拟机 【自定义】 点击“下一步”,此处【默认】,再点击“下一步”。 点击“稍后安装操作系统”,再点击“下一步”。 点击“Linux(L)”,版本选择【Ubuntu 64 位】,再点击…

轻量级网页RSS阅读器selfoss

什么是 selfoss ? selfoss 是一个多用途的 RSS 阅读器和提要聚合 Web 应用程序。它使您可以在一个地方轻松关注来自不同网站、社交网络和其他平台的更新。它是用 PHP 编写的,基本上可以让您在任何地方运行它。 安装 在群晖上以 Docker 方式安装。 在注…

【前沿技术】问答pk【ChatGPT Vs Notion AI Vs BAT AI 】

目录 写在前面 问题: 1 ChatGPT 1.1 截图 ​1.2 文字版 2 Notion AI 2.1 截图 2.2 文字版 3 BAT AI 3.1 截图 3.2 文字版 总结 序言 所有幸运和巧合的事,要么是上天注定,要么是一个人偷偷的在努力。 突发奇想,问三个…

机器学习---聚类算法

目录【写在前面】1、确认安装有scikit-learn库2、使用 make _ classification ()建立数据集3、使用模型进行分类头文件汇总亲和力传播聚合聚类BIRCH 聚类DBSCAN【本人的毕业设计系统中有用到】K-均值高斯混合模型【写在最后】【写在前面】 sklearn和scikit-learn: …

软件测试需要学什么

软件测试近些年也是比较热门的行业,薪资高、入门门槛低,让很多开发人员想纷纷加入软件开发这个行业,想要成为这一岗位的一员,想要进入软件测试行业,他们需要学习什么呢? 软件测试需要学习的还挺多的&#…

Flowable开源版和Flowable商业版有什么区别?

Flowable除了提供开源版本flowable-engine,它还提供了一系列基于Flowable引擎的快速、现代和完全可定制的企业产品(商业收费):Flowable Work、Flowable Orchestrate和Flowable Engage。Flowable的开源版本和商业版本有什么区别&am…

【产线事故】分享生产线事故发生的一次OOM

文章目录前言OutOfMemoryError出现的原因常见堆内存溢出的几种情况现象分析Mybatis源码分析情景复现总结前言 继上次线上CPU出现了报警,这次服务又开始整活了,风平浪静了没几天,看生产日志服务的运行的时候,频繁的出现OutOfMemor…

接口自动化测试如何做?测试老鸟总结,接口测试数据构造大全......

目录:导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜)前言 接口参数的数据获取…

Linux复习 / 线程相关----线程概念与控制 QA梳理

文章目录前言Q&A线程概念Q:线程和进程的区别?(为什么要有线程,从进程的角度说明这个问题)Q:Linux是如何设计线程的?Q:学习了线程后,你能说说进程和线程最大的区别是什…

博客系统(后端编程)

这里还是这四个页面: 博客列表页 博客详情页 登录页 博客编辑页 一、准备工作: 1.引入依赖 引入mysql,servlet,jackson的依赖,并且把之前的前端页面拷贝进去. 2.创建目录 并且把相关代码复制进去. 此时目录就完成了!!! 3.复制前端代码 直接ctrlv我们之前的前端代码到web…

目标检测YOLO系列-YOLOV7运行步骤(推理、训练全过程)

下载源代码:点击下载 进入项目根目录并执行以下命令安装requirements.txt中的相关依赖 pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple官网下载权重yolov7.pt(测试使用)、yolov7-tiny.pt(训练使用…

【C++】哈希表:开散列和闭散列

📝 个人主页 :超人不会飞)📑 本文收录专栏:《C的修行之路》💭 如果本文对您有帮助,不妨点赞、收藏、关注支持博主,我们一起进步,共同成长! 目录前言一、基于哈希表的两个…

Spring MVC请求处理流程分析

Spring MVC请求处理流程分析一 Spring MVC 请求处理流程二 Spring MVC 请求处理流程源码分析2.1架构图解2.2 重要时机点分析2.3核心步骤分析2.3.1 getHandler⽅法剖析2.3.2 getHandlerAdapter⽅法剖析2.3.3 ha.handle⽅法剖析2.3.4 processDispatchResult⽅法剖析三 Spring MVC…

Ruby2D总结

Ruby学习心得 学了几天,Ruby2D这个项目我差不多把教程里面的东西做完了,感觉还好,只要每天一有空的话就去做的话就可以快速做好一个项目,不过还是会有一点虚浮感,但学习也是一个不能拖的事情,所以为了平衡…