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

文章目录

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

锁策略

乐观锁和悲观锁

乐观锁

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

悲观锁

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

两者的比较

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

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


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

读写锁

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

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

因此读写锁,也就诞生了,那么读写锁是怎么进行加锁的呢?按照字面意思肯定就是按照一个线程是读还是写来区别加锁了。那么既然是按照意图来进行区别加锁的我们首先当然要清除这个线程想要进行的操作是什么才可以来进行加锁。也就是加锁前需要获取这个线程的行为意图。
读写锁就是把读操作和写操作区分对待. 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.mzph.cn/news/793472.shtml

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

相关文章

网络原理 - HTTP / HTTPS(4)——构造http请求

目录 一、postman 的下载安装以及简单介绍 1、下载安装 2、postman的介绍 二、通过 Java socket 构造 HTTP 请求 构造http请求的方式有两种:(1)通过代码构造(有一点难度) (2)通过第三…

Anaconda/Python快速安装jieba 【win/mac】

一、直接上命令 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple jieba 我是在PyCharm里面的终端输进去。 之后就很快速的看到成功的下图。 二、官网 官网下载的速度太慢了——这是官网地址https://pypi.org/project/jieba/#files 点进去之后点击下载&#xff0c…

【卷积神经网络进展】

打基础日常记录 CNN基础知识1. 感知机2. DNN 深度神经网络(全连接神经网络)DNN 与感知机的区别DNN特点,全连接神经网络DNN前向传播和反向传播 3. CNN结构【提取特征分类】4. CNN应用于文本 CNN基础知识 1. 感知机 单层感知机就是一个二分类…

Mysql不同条件设置相同的值(使用子查询)

WHEN type1 THEN payable_price WHEN type2 THEN payable_price ELSE MAX(payable_price) type1 表示订单维度,type2表示商品维度,需要无论type值为多少都取type1时的payable_price值 解决方案: 使用SQL子查询; SELECT CASE WHEN type …

利用AI结合无极低码(免费版)快速实现接口开发教程,会sql即可,不需要编写编译代码

无极低码无代码写服务+AI实践 本次演示最简单的单表无代码增删改查发布服务功能,更复杂的多表操作,安全验证,多接口调用,自自动生成接口服务,生成二开代码,生成调用接口测试,一键生成管理界面多条件检索、修改、删除、查看、通用公共接口调用、通用无限级字典调用等后续…

Java的Cookie和Session配合解决会话管理问题

目录 会话管理概述 为什么需要会话管理 会话管理实现的手段 Cookie Cookie概述 Cookie的使用 Cookie的时效性 Cookie的提交路径 Session HttpSession概述 HttpSession的使用 HttpSession时效性 cookie和session结合使用 会话管理概述 为什么需要会话管理 在Java…

【Java入门教程】第二十讲:集合和常见操作

集合框架(Collection)是 Java 编程语言中一个非常重要的组成部分,它为存储和操作数据提供了一套灵活而强大的API。 本文将详细介绍Java集合框架的基本概念、常用接口和实现类,并通过代码示例来加深理解,帮助大家更好地…

Vue中生成二维码,使用现有的二维码库qrcode

要在Vue中生成二维码,你可以使用现有的二维码库,如qrcode。首先,你需要安装这个库。在你的项目目录下,运行以下命令: bash 复制 npm install qrcode --save 然后,在你的Vue组件中,你可以这样使…

ssm基于jsp的学生作业管理系统论文

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本学生作业管理系统就是在这样的大环境下诞生,其可以帮助管理者在短时间内处理完毕庞大的数据信息…

C#(C Sharp)学习笔记_Enum枚举类型【十三】

什么是枚举类型 枚举类型(Enum) 是由基础整型数值类型的一组命名常量定义的值类型。枚举包含自己的值,但不能继承或传递继承。 语法 // enum enum_name // enum_name variable enum_name.enum_value// 定义一个枚举类型——例如: enum enum_name {va…

【MATLAB源码-第30期】基于matlab的内边界边缘检测算法。

操作环境: MATLAB 2022a 1、算法描述 在计算机视觉领域,图像分割(segmentation)指的是将数字图像细分为多个图像子区域(像素的集合)(也被称作超像素)的过程。图像分割的目的是简化…

查找算法第1篇

查找,又称搜索,检索。 查找运算的主要操作是关键字的比较, 通常把查找过程中的平均比较次数(也称为平均查找长度) 作为衡量一个查找算法效率优劣的标准。 平均查找长度(Average Search. Length ASL) 的计算公式为 A S L ∑ i 1 n P n C i…

mysql常见故障

目录 1. 连接问题 2. 数据库无法启动 3. 数据库崩溃 4. 慢查询 5. 主从同步问题 6. 硬件故障 7. 日志问题 8. 其他常见问题 注意事项 1. ERROR 1045 (28000): Access denied for user userhost (using password: YES) 2. ERROR 2002 (HY000): Cant connect to local…

【DevOps】使用Filebeat收集华为云cce containerd日志

目录 1、背景2、containerd日志路径3、收集日志1、背景 将 Docker 换成 containerd 作为 Kubernetes (K8s) 集群中的容器运行时有以下几个好处: 性能提升: containerd 相较于 Docker,其设计更为精简,专注于容器的生命周期管理,没有Docker包含的其他额外服务如API服务器…

突破编程_C++_网络编程(TCPIP 四层模型(概述))

1 TCP/IP概述 1.1 TCP/IP的定义与起源 TCP/IP 协议,全称为 Transmission Control Protocol/Internet Protocol,中文名为传输控制协议/因特网互联协议,又名网络通讯协议。这是 Internet 最基本的协议,也是 Internet 国际互联网络…

【云原生篇】K8S之DaemonSet 详解

Kubernetes 的 DaemonSet 是一种特殊的工作负载控制器,它确保所有(或某些特定的)节点上都运行一个 Pod 的副本。当有新节点加入集群时,DaemonSet 会自动在新节点上添加相应的 Pod,当节点从集群中移除时,这些…

PWM模块的中断

在PWM模块中使用中断的主要目的是为了实现定时中断功能。PWM(脉宽调制)是一种通过调节信号的脉冲宽度来控制输出电压或电流的技术,在嵌入式系统中广泛应用于控制电机、LED亮度调节等领域。而在某些应用场景下,需要在PWM周期内定时…

sentinel与nacos集成

前言 sentinel的规则可以通过编码方式定义,也可以通过配置方式定义。sentinel-dashboard提供了界面维护功能,但是配置是存储在内存中的。因此需要进行持久化。 Sentinel自身就支持了多种不同的数据源来持久化规则配置,目前包括以下几种方式…

Swing中的FlowLayout/WrapLayout在打横排列时候如何做到置顶对齐

前言 最近在开发swing客户端时候碰到一个棘手的问题: Swing中的FlowLayout/WrapLayout在打横排列时候如何做到置顶对齐如果是vue或者react,一搜百度什么都出来了,swing的话,嗯。。。资料有点少而且大部分是stack overflow上面的…

Docker环境安装Postgresql数据库Posrgresql 15.6

宿主机是ubuntu 22.04版本 ubuntu宿主机上安装docker,参见官方文档https://docs.docker.com/engine/install/ubuntu/, docker-ce是社区版 docker-ee是企业版 1、检查Docker是否安装 rootODS1SPGOFSDEV:~# docker Command docker not found, but can be installed …