JAVAEE——多线程进阶,锁策略

news2024/11/25 6:44:21

文章目录

  • 锁策略
    • 乐观锁和悲观锁
      • 乐观锁
      • 悲观锁
        • 两者的比较
    • 读写锁
    • 重量级锁和轻量级锁
      • 重量级锁
      • 轻量级锁
    • 自旋锁
    • 公平锁和非公平锁
      • 公平锁
      • 非公平锁
    • 可重入锁和不可重入锁
      • 可重入锁
      • 不可重入锁

锁策略

乐观锁和悲观锁

乐观锁

什么是乐观锁呢?我们可以认为乐观锁比较自信,当多线程执行的时候如果要对一个资源进行访问,那么乐观锁会认为这些线程的访问是不会造成冲突的,并且这些访问也不都是要进行修改。因此对这些线程访问更新的时候乐观锁才会进行检测查看这个进程的访问是否会造成冲突,如果会的话就返回错误信息由用户决定是否如何去做

悲观锁

悲观锁相较于乐观锁也是一种极端,悲观锁认为只要访问就一定会造成并发冲突,因此悲观锁认为只要是访问资源,都必须加上锁,这样当别人想要获取这个资源的时候就必须获取这把锁陷入了阻塞等待当中。

两者的比较

这里我们举一个例子来说明

假如说甲乙两位同学向老师请问问题,那么甲是一个悲观的人,乙是一个乐观的人,甲突然去找老师,老师肯定在忙碌无法给自己将题目,因此会先给老师发个消息询问老师是否在忙碌当得到老师的答复之后再决定是继续等待还是直接过去,而乙则是比较乐观,认为自己现在过去不会打扰到老师,老师可以立即解答自己的疑惑,因此乙就会直接过去询问老师问题,这时候可能老师确实没有忙碌可以直接解决问题也有可能老师是在忙碌的,这时候乙就需要进行等待了。


结论:两把锁各有特点针对于不同的场合使用不同的锁没有什么优劣性比较。

读写锁

读写锁。线程对一个资源的访问是分为读操作和写操作的,那么对于一个资源来说读操作是不会导致线程不安全的只有写操作才会导致线程不安全,因此线程对一个资源的访问加锁我们也可以分为读锁和写锁来进行,因此我们就需要搞明白哪些情况会导致线程不安全

  • 线程同时去读取一个数据:安全的
  • 一批线程去读另一批线程在写:不安全
  • 线程都在写:不安全

因此读写锁,也就诞生了,那么读写锁是怎么进行加锁的呢?按照字面意思肯定就是按照一个线程是读还是写来区别加锁了。那么既然是按照意图来进行区别加锁的我们首先当然要清除这个线程想要进行的操作是什么才可以来进行加锁。也就是加锁前需要获取这个线程的行为意图。
读写锁就是把读操作和写操作区分对待. Java 标准库提供了 ReentrantReadWriteLock 类, 实现了读写
锁.
我们来写一个示例代码运行一下查看

import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class Lock_policy  {
    public static  int tmp=10;
    public static final ReentrantReadWriteLock wrlock=new ReentrantReadWriteLock();
    public static void main(String[] args) {
            Thread t1=new Thread(()->{
                wrlock.readLock().lock();
                System.out.println("我是t1线程"+tmp);
                //wrlock.readLock().unlock();

            });
            Thread t2=new Thread(()->{
                wrlock.readLock().lock();
                System.out.println("我是t2线程"+tmp);
                //wrlock.readLock().unlock();
            });
            Thread t3=new Thread(()->{
                wrlock.writeLock().lock();
                tmp++;
                System.out.println("我是t3线程"+tmp);
            });
            t1.start();
            t2.start();
    }
}

首先我们可以观察到这个代码中我们创建的t3线程并没有start运行因此我们测试的是当两个线程同时加上读锁并且读一个数据的时候是否会阻塞我们看一下运行结果。
在这里插入图片描述
结果很明显程序正常跑完因此没有任何的阻塞。我们来试试把t3线程运行试试结果。

import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class Lock_policy  {
    public static  int tmp=10;
    public static final ReentrantReadWriteLock wrlock=new ReentrantReadWriteLock();
    public static void main(String[] args) {
            Thread t1=new Thread(()->{
                wrlock.readLock().lock();
                System.out.println("我是t1线程"+tmp);
                //wrlock.readLock().unlock();

            });
            Thread t2=new Thread(()->{
                wrlock.readLock().lock();
                System.out.println("我是t2线程"+tmp);
                //wrlock.readLock().unlock();
            });
            Thread t3=new Thread(()->{
                wrlock.writeLock().lock();
                tmp++;
                System.out.println("我是t3线程"+tmp);
            });
            t1.start();
            t2.start();
            t3.start();
    }
}

运行截图如下
在这里插入图片描述
那么是否只有这一种结果呢?当然不是。
在这里插入图片描述
在实验的过程中我们可能产生这些不同的结果那么这是为什么呢?原因很简单那就是因为t3线程在t1和t2线程获取读锁之前就已经加上了写锁导致了t1和t2的读操作阻塞了。那么无论上述的哪种 结果都是可以说明读写锁中读锁和写锁是阻塞的。

重量级锁和轻量级锁

重量级锁

在理解这里的时候我们要先搞明白什么是重量级锁。顾名思义听名字就感觉这个锁很慢,那么这种原因究竟是为什么呢?这就要追溯到锁的一个机制了。


我们要搞明白加锁是为了干什么?很简单加锁是为了保证我们的多个操作是原子性的。原子性的保证使得我们的操作避免了多线程的安全问题。那么为什么锁可以保证操作的原子性呢?其实说白了还是因为我们的硬件设备的支持也就是底层建筑决定上层建筑,因为我们的硬件支持,所以我们的操作系统可以给我们提供一系列的锁的操作接口,而操作系统提供的接口就是mutex。

  • CPU 提供了 “原子操作指令”.
  • 操作系统基于 CPU 的原子指令, 实现了 mutex 互斥锁.
  • JVM 基于操作系统提供的互斥锁, 实现了 synchronized 和 ReentrantLock 等关键字和类
    在这里插入图片描述

重量级锁:加锁机制非常依赖于OS提供的mutex因此在加锁的时候涉及到大量的从内核态到用户态的转变,效率较低。

轻量级锁

轻量级锁即加锁的时候尽量不依赖于mutex而是尽量在用户态代码完成. 实在搞不定了, 再使用 mutex。那么这时候有些美女或者帅哥可能就会很混乱,说的直白一些就是,轻量级锁就是尽量不去调用系统接口他就是一个优化。

自旋锁

什么是自旋锁呢?那么按照我们之前写的代码当我们的锁被抢占的时候如果我们也想抢占这把锁的话就需要先进行阻塞等待也就是wait然后等待被唤醒,可是我们不希望这样怎么办?也就是说可能当前占有锁的这个进程很快就结束了就要释放这把锁了

公平锁和非公平锁

公平锁

公平锁遵守先来后到的原则B比C先来的那么当A释放锁之后B就会比C先获取到释放的锁

非公平锁

不遵守先来后到的原则,synchronized()就是一个非公平锁,他的调度顺序是有操作系统决定的。

  • 操作系统内部的线程调度就可以视为是随机的. 如果不做任何额外的限制, 锁就是非公平锁. 如果要
    想实现公平锁, 就需要依赖额外的数据结构, 来记录线程们的先后顺序.
  • 公平锁和非公平锁没有好坏之分, 关键还是看适用场景.

可重入锁和不可重入锁

可重入锁

可重入的意思就是同一个线程可以多次获取同一把锁。也就是可以重新进入的锁。synchorinzed就是一把可重入锁。Java里只要以Reentrant开头命名的锁都是可重入锁,而且JDK提供的所有现成的Lock实现类,包括
synchronized关键字锁都是可重入的。

不可重入锁

不可重入锁就是当自己这个线程要重新申请这把锁的时候要进行等待便是不可重入锁。

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

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

相关文章

MySQL 连接池的实现

池化技术 池化技术能够减少资源对象的创建次数,提高程序的响应性能,特别是在高并发下这种提高更明显。共同特征 对象创建时间长。对象创建需要大量资源。对象创建后可被重复使用。 数据库连接池 数据库连接池(Connection pooling&#xff…

linux C:变量、运算符

linux C 文章目录 变量运算符 一、变量 [存储类型] 数据类型 标识符 值 标识符:由数字、字母、下划线组成的序列,不能以数字开头。 数据类型:基本数据类型构造类型 存储类型:auto static…

2.4_2 死锁的处理策略——预防死锁

2.4_2 死锁的处理策略——预防死锁 知识总览 #mermaid-svg-z0noPuUcH4CJsxb7 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-z0noPuUcH4CJsxb7 .error-icon{fill:#552222;}#mermaid-svg-z0noPuUcH4CJsxb7 .error-t…

【BlossomRPC】接入注册中心

文章目录 NacosZookeeper自研配置中心 RPC项目 配置中心项目 网关项目 这是BlossomRPC项目的最后一篇文章了,接入完毕注册中心,一个完整的RPC框架就设计完成了。 对于项目对注册中心的整合,其实我们只需要再服务启动的时候将ip/port/servic…

商城业务-检索服务

文章目录 前言一、搭建页面环境1.1 静态界面搭建1.2 Nginx 动静分离1.3 Windows 上传文件1.4 引入 thymeleaf 依赖1.5 Nginx 反向代理1.4 Nginx 配置1.5 gateway 网关配置 二、调整页面跳转2.1 引入依赖2.2 页面跳转 三、检索查询参数模型分析抽取3.1 检索业务分析3.2 检索语句…

齿轮“红宝书”

​在齿轮行业,有两本书被广大从业者尊称为“红宝书”。这两部作品深入剖析了齿轮技术的精髓,为从业者提供了宝贵的指导和启示。它们犹如行业的明灯,照亮了齿轮制造的每一个角落,使得从业者在探索中不再迷茫。 这两本红宝书的内容…

遥感动态监测技术

很多人对动态监测和动态检测两个名词有疑惑。我们可以这样理解,动态监测是一个广义的名词,泛指数据预处理、变化信息发现与提取、变化信息挖掘与应用等,以对整个流程的叙述。动态检测是一个狭义的名词,主要指部分数据预处理、变化…

【御控物联】JavaScript JSON结构转换(7):数组To数组——键值互换属性重组

文章目录 一、JSON结构转换是什么?二、案例之《JSON数组 To JSON数组》三、代码实现四、在线转换工具五、技术资料 一、JSON结构转换是什么? JSON结构转换指的是将一个JSON对象或JSON数组按照一定规则进行重组、筛选、映射或转换,生成新的JS…

前端(三)React踩坑记录

一、引言 作者最近新的平台项目是需要用react的,和vue区别还是比较大的,这里记录下踩坑和使用经验。 二、环境 框架:antd 依赖: "dependencies": {"ant-design/icons": "^4.7.0","ant-desig…

Linux使用Docker部署RStudio Server结合内网穿透实现公网访问本地服务

文章目录 前言1. 安装RStudio Server2. 本地访问3. Linux 安装cpolar4. 配置RStudio server公网访问地址5. 公网远程访问RStudio6. 固定RStudio公网地址 前言 RStudio Server 使你能够在 Linux 服务器上运行你所熟悉和喜爱的 RStudio IDE,并通过 Web 浏览器进行访问…

卷积层+多个输入通道

卷积层多输入输出通道 在深度学习中,卷积神经网络(CNN)通常用于处理具有多个输入通道的数据。当输入数据具有多个通道(例如彩色图像的RGB通道)时,卷积操作可以同时在每个通道上进行,并将各通道的…

【成功案例】间隔数月双团伙先后利用某ERP0day实施入侵和勒索的解密恢复项目

1.背景 在2024年3月23日,我们的Solar应急响应团队(以下简称Solar团队)应某公司之邀,介入处理了一起财务系统服务器遭受黑客攻击的事件。该事件导致服务器上大量文件被加密。我们的团队迅速获取了一个被加密的文件,并立…

面试题:MySQL 优化篇

定位慢查询 💖 开源工具 调试工具:Arthas(阿尔萨斯)运维工具:Prometheus(普罗米修斯)、Skywalking 💖 MySQL 慢查询日志 # 开启 MySQL 慢查询日志开关 slow_query_log1 # 设置慢…

HWOD:整型数组排序

一、知识点 while(1){}表示永久循环 使用break结束循环 二、题目 1、描述 输入整型数组和排序标识&#xff0c;对其元素按照升序或降序进行排序 2、数据范围 1<n<1000 0<val<100000 3、输入 第一行输入数组元素个数 第二行输入待排序的数组&#x…

安装JupyterLab的集成环境

Python集成环境安装 不要半途而废&#xff0c;不要作业太多就抛下你手中的笔&#xff0c;拿起你旁边的手机&#xff0c;你觉得这样很有意义吗&#xff1f;一个小时一道题都没做&#xff0c;盯着手机屏幕它能给你一个未来吗&#xff1f;少分心就能多做一道题&#xff0c;多学样本…

编程新手必看,Python开发环境工具揭秘:高效编程的必备工具(2)

1、Python主流的开发工具介绍&#xff1a; Python的主流开发工具主要包括PyCharm、Visual Studio Code&#xff08;VS Code&#xff09;、IDLE等。具体介绍如下&#xff1a; 1.1、PyCharm&#xff1a; PyCharm是由JetBrains开发的&#xff0c;专为Python设计的IDE&#xff0…

生成 SSH 公钥

Windows 用户建议使用 Windows PowerShell 或者 Git Bash&#xff0c;在 命令提示符 下无 cat 和 ls 命令。 1、通过命令 ssh-keygen 生成 SSH Key&#xff1a; ssh-keygen -t ed25519 -C "Gitee SSH Key"-t key 类型 -C 注释 输出&#xff0c;如&#xff1a; 中间…

【tensorflow框架神经网络实现鸢尾花分类_Keras】

文章目录 1、前言2、鸢尾花分类3、结果打印 1、前言 【tensorflow框架神经网络实现鸢尾花分类】一文中使用自定义的方式&#xff0c;实现了鸢尾花数据集的分类工作。在这里使用tensorflow中的keras模块快速、极简实现鸢尾花分类任务。 2、鸢尾花分类 import tensorflow as t…

python如何画奥运五环

绘制奥运五环主要涉及到Python中的turtle绘图库运用&#xff1a; 程序源代码为&#xff1a; import turtle turtle.width(10) turtle.color(black) turtle.circle(50) turtle.penup() turtle.goto(120,0) turtle.pendown() turtle.color(red) turtle.circle(50) turtle.penup()…