java高并发系列-第2天:并发级别

这是java高并发系列第2篇文章,一个月,咱们一起啃下java高并发,欢迎留言打卡,一起坚持一个月,拿下java高并发。

由于临界区的存在,多线程之间的并发必须受到控制。根据控制并发的策略,我们可以把并发的级别分为阻塞无饥饿无障碍无锁无等待几种。

阻塞

一个线程是阻塞的,那么在其他线程释放资源之前,当前线程无法继续执行。当我们使用synchronized关键字或者重入锁时,我们得到的就是阻塞的线程。

synchronize关键字和重入锁都试图在执行后续代码前,得到临界区的锁,如果得不到,线程就会被挂起等待,直到占有了所需资源为止。

无饥饿(Starvation-Free)

如果线程之间是有优先级的,那么线程调度的时候总是会倾向于先满足高优先级的线程。也就是说,对于同一个资源的分配,是不公平的!图1.7中显示了非公平锁与公平锁两种情况(五角星表示高优先级线程)。对于非公平锁来说,系统允许高优先级的线程插队。这样有可能导致低优先级线程产生饥饿。但如果锁是公平的,按照先来后到的规则,那么饥饿就不会产生,不管新来的线程优先级多高,要想获得资源,就必须乖乖排队,这样所有的线程都有机会执行。

图片

无障碍(Obstruction-Free)

无障碍是一种最弱的非阻塞调度。两个线程如果无障碍地执行,那么不会因为临界区的问题导致一方被挂起。换言之,大家都可以大摇大摆地进入临界区了。那么大家一起修改共享数据,把数据改坏了怎么办呢?对于无障碍的线程来说,一旦检测到这种情况,它就会立即对自己所做的修改进行回滚,确保数据安全。但如果没有数据竞争发生,那么线程就可以顺利完成自己的工作,走出临界区。

如果说阻塞的控制方式是悲观策略,也就是说,系统认为两个线程之间很有可能发生不幸的冲突,因此以保护共享数据为第一优先级,相对来说,非阻塞的调度就是一种乐观的策略。它认为多个线程之间很有可能不会发生冲突,或者说这种概率不大。因此大家都应该无障碍地执行,但是一旦检测到冲突,就应该进行回滚。

从这个策略中也可以看到,无障碍的多线程程序并不一定能顺畅运行。因为当临界区中存在严重的冲突时,所有的线程可能都会不断地回滚自己的操作,而没有一个线程可以走出临界区。这种情况会影响系统的正常执行。所以,我们可能会非常希望在这一堆线程中,至少可以有一个线程能够在有限的时间内完成自己的操作,而退出临界区。至少这样可以保证系统不会在临界区中进行无限的等待。

一种可行的无障碍实现可以依赖一个"一致性标记"来实现。线程在操作之前,先读取并保存这个标记,在操作完成后,再次读取,检查这个标记是否被更改过,如果两者是一致的,则说明资源访问没有冲突。如果不一致,则说明资源可能在操作过程中与其他线程冲突,需要重试操作。而任何对资源有修改操作的线程,在修改数据前,都需要更新这个一致性标记,表示数据不再安全。

数据库中乐观锁,应该比较熟悉,表中需要一个字段version(版本号),每次更新数据version+1,更新的时候将版本号作为条件进行更新,根据更新影响的行数判断更新是否成功,伪代码如下:

 
  1. 1.查询数据,此时版本号为w_v

  2. 2.打开事务

  3. 3.做一些业务操作

  4. 4.update t set version = version+1 where id = 记录id and version = w_v;//此行会返回影响的行数c

  5. 5.if(c>0){

  6. //提交事务

  7. }else{

  8. //回滚事务

  9. }

多个线程更新同一条数据的时候,数据库会对当前数据加锁,同一时刻只有一个线程可以执行更新语句。

无锁(Lock-Free)

无锁的并行都是无障碍的。在无锁的情况下,所有的线程都能尝试对临界区进行访问,但不同的是,无锁的并发保证必然有一个线程能够在有限步内完成操作离开临界区。

在无锁的调用中,一个典型的特点是可能会包含一个无穷循环。在这个循环中,线程会不断尝试修改共享变量。如果没有冲突,修改成功,那么程序退出,否则继续尝试修改。但无论如何,无锁的并行总能保证有一个线程是可以胜出的,不至于全军覆没。至于临界区中竞争失败的线程,他们必须不断重试,直到自己获胜。如果运气很不好,总是尝试不成功,则会出现类似饥饿的先写,线程会停止。

下面就是一段无锁的示意代码,如果修改不成功,那么循环永远不会停止。

 
  1. while(!atomicVar.compareAndSet(localVar, localVar+1)){

  2. localVal = atomicVar.get();

  3. }

无等待

无锁只要求有一个线程可以在有限步内完成操作,而无等待则在无锁的基础上更进一步扩展。它要求所有线程都必须在有限步内完成,这样不会引起饥饿问题。如果限制这个步骤的上限,还可以进一步分解为有界无等待和线程数无关的无等待等几种,他们之间的区别只是对循环次数的限制不同。

一种典型的无等待结果就是RCU(Read Copy Update)。它的基本思想是,对数据的读可以不加控制。因此,所有的读线程都是无等待的,它们既不会被锁定等待也不会引起任何冲突。但在写数据的时候,先获取原始数据的副本,接着只修改副本数据(这就是为什么读可以不加控制),修改完成后,在合适的时机回写数据。

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

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

相关文章

P6入门:项目初始化7-项目详情之代码/分类码Code

前言 使用项目详细信息查看和编辑有关所选项目的详细信息,在项目创建完成后,初始化项目是一项非常重要的工作,涉及需要设置的内容包括项目名,ID,责任人,日历,预算,资金,分类码等等&…

排序算法之-快速

算法原理 丛待排序的数列中选择一个基准值,通过遍历数列,将数列分成两个子数列:小于基准值数列、大于基准值数列,准确来说还有个子数列:等于基准值即: 算法图解 选出基准元素pivot(可以选择…

P36[11-1]SPI通信协议

SPI相比于IIC的优缺点: 1.SPI传输速度快(IIC高电平驱动能力较弱,因此无法高速传输) 2.使用简单 3.通信线多 SCK(SCLK,CK,CLK):串行时钟线 MOSI(DO):主机输出,从机输入 MISO(DI): 主机输入,从机输出 SS(NSS,CS):从机选择(有多少个从机,主机就要用几根SS分别与从机连接…

Windows环境下ADB调试——安装adb

一、下载 Windows版本:https://dl.google.com/android/repository/platform-tools-latest-windows.zipMac版本:https://dl.google.com/android/repository/platform-tools-latest-darwin.zipLinux版本:https://dl.google.com/android/reposit…

HTTP服务器——tomcat的安装和使用

文章目录 前言下载tomcattomcat 文件bin 文件夹conf 文件lib 文件log 文件temp 文件webapps 文件work 目录 如何使用 tomcat 前言 前面我们已经学习了应用层协议 HTTP 协议和 HTTP 的改进版——HTTPS,这些协议是我们在写与服务器相关的代码的时候息息相关的&#x…

专访|OpenTiny 社区 Mr 栋:结合兴趣,明确定位,在开源中给自己一些技术性挑战

前言 OpenTiny 开源之夏项目终于迎来了圆满的结局。借此机会,我们采访了 TinyReact 的共建者 Mr 栋同学。 Mr 栋同学是一位热衷于前端技术的开发者,对前端开发充满了激情和热爱。同时他也是一位即将毕业的大四在校生。在 OpenTiny 开源项目中&#xff0…

Java18新增特性

前言 前面的文章,我们对Java9、Java10、Java11、Java12 、Java13、Java14、Java15、Java16、Java17 的特性进行了介绍,对应的文章如下 Java9新增特性 Java10新增特性 Java11新增特性 Java12新增特性 Java13新增特性 Java14新增特性 Java15新增特性 Java…

做一个Sprngboot文件上传-阿里云

概述 这个模块是用来上传头像以及文章封面的,图片的值是一个地址字符串,一般存放在本地或阿里云服务中 1、本地文件上传 我们将文件保存在一个本地的文件夹下,由于可能两个人上传不同图片但是却同名的图片,那么就会一个人的图片就…

Mac 本地部署thinkphp8【部署环境以及下载thinkphp】

PHP的安装以及环境变量配置 1 PHP安装:在终端输入brew install php 这里是PHP下载的最新的 如果提示‘brew’找不到,自己搜索安装吧, 不是特别难 2 环境变量配置 终端输入vim ~/.bash_profile 输入export PATH"/usr/local/Cellar/php/8.…

ubuntu18.04安装google浏览器

下载google安装包 wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb 安装google浏览器 sudo dpkg -i google-chrome-stable_current_amd64.deb 执行安装 sudo apt-get -f install 启动浏览器 在应用程序中找到google图标点击运行

安全区域边界(设备和技术注解)

网络安全等级保护相关标准参考《GB/T 22239-2019 网络安全等级保护基本要求》和《GB/T 28448-2019 网络安全等级保护测评要求》 密码应用安全性相关标准参考《GB/T 39786-2021 信息系统密码应用基本要求》和《GM/T 0115-2021 信息系统密码应用测评要求》 1边界防护 1.1应保证跨…

Spark数据倾斜优化

1 数据倾斜现象 1、现象 绝大多数task任务运行速度很快,但是就是有那么几个task任务运行极其缓慢,慢慢的可能就接着报内存溢出的问题。 2、原因 数据倾斜一般是发生在shuffle类的算子,比如distinct、groupByKey、reduceByKey、aggregateByKey…

vue脚手架初始化项目搭建后配置路由【小白易学】

首先这里你已经创建好项目了,这是跑起来的效果 首先第一步,需要下载路由router npm install vue-router4下载好了之后找到main.js页面,加入router import { createApp } from vue; import App from ./App.vue; import router from ./routercreateApp(A…

采集标准Docker容器日志:部署阿里云Logtail容器以及创建Logtail配置,用于采集标准Docker容器日志

文章目录 引言I 预备知识1.1 LogtailII 查询语法2.1 具体查询语法2.2 查询示例2.3 设置token时间(登录过期时间)see also引言 I 预备知识 1.1 Logtail Logtail是日志服务提供的日志采集Agent,用于采集阿里云ECS、自建IDC、其他云厂商等服务器上的日志。本文介绍Logtail的功…

RTOS实时操作系统在嵌入式开发中的应用

随着各种嵌入式系统应用的日益复杂和对实时性要求的提高,使用实时操作系统(RTOS)成为嵌入式开发中的一种重要选择。STM32微控制器作为一种强大的嵌入式处理器,与各种RTOS相结合,能够提供更高效、可靠并且易于维护的系统…

ESP32网络开发实例-BME280传感器数据保存到InfluxDB时序数据库

BME280传感器数据保存到InfluxDB时序数据库 文章目录 BME280传感器数据保存到InfluxDB时序数据库1、BM280和InfluxDB介绍2、软件准备3、硬件准备4、代码实现在本文中,将详细介绍如何将BME280传感器数据上传到InfluxDB中,方便后期数据处理。 1、BM280和InfluxDB介绍 InfluxDB…

postgreSQL中的高速缓存

1. 高速缓存简介 ​如下图所示,当一个postgreSQL进程读取一个元组时,需要获取表的基本信息(例如:表的oid、索引信息和统计信息等)及元组的模式信息,这些信息被分别记录在多个系统表中。通常一个表的模式信…

果园自主跟随碎枝机器人

开发背景 农业扶贫项目—— 开发一款适用于猕猴桃果园的跟随碎枝机器人。 在猕猴桃的种植培育过程中,一项非常重要的环节便是剪枝,通常有冬剪和夏剪。以往果农剪完枝条后要将散落于地的枝条归拢后统一粉碎还田。这需要专门收集地面上的枝条并将其归拢到…

C语言指针进阶

文章目录 1.字符指针1.1字符1.2字符串 2.数组指针2.2数组名和&数组名2.3数组指针的使用2.3.1一维数组例子2.3.2 二维数组传参2.3.2.1参数是数组的形式2.3.2.2参数是指针的形式 3.指针数组4.数组传参和指针传参4.1 一维数组传参4.1.1参数为数组的形式,参数为指针…

windows系统用于 SDN 的软件负载均衡器 (SLB)

适用于:Azure Stack HCI 版本 22H2 和 21H2;Windows Server 2022、Windows Server 2019、Windows Server 2016 软件负载均衡器包括哪些内容? 软件负载均衡器提供以下功能: 适用于北/南和东/西 TCP/UDP 流量的第 4 层 (L4) 负载均…