简单聊一聊公平锁和非公平锁,parallel并行流
目录
- 一、降低锁的粒度,将synchronized关键字不放在方法上了,改为synchronized代码块。
- 二、先区分一下公平锁和非公平锁
- 1、公平锁
- 2、非公平锁
- 3、公平锁的优缺点:
- 4、非公平锁的优缺点:
- 三、是否对症下药
- 四、IntStream.rangeClosed是干嘛的?
- 五、parallel是干嘛的?
- 1、parallel()是什么
- 2、举一个简单的demo
- 3、parallel()的优缺点
- 4、何时使用parallel()?
大家好,我是哪吒。
上一章提到了i++的线程安全问题,最终方案是在两个方法上添加synchronized关键字,从而避免i++的线程安全问题,不过,这样真的好吗?在所有有线程安全的方法都添加synchronized?
答案是显而易见的,不行。
synchronized会极大的降低程序的性能,导致整个程序几乎只能支持单线程操作,性能显著降低。
那么,如何解决呢?
一、降低锁的粒度,将synchronized关键字不放在方法上了,改为synchronized代码块。
锁的粒度更小了,也解决了这个问题,确实可以的。
package com.guor.thread;public class SynchronizedTest2 {int a = 1;int b = 1;public void add() {System.out.println("add start");synchronized (this) {for (int i = 0; i < 10000; i++) {a++;b++;}}System.out.println("add end");}public synchronized void compare() {System.out.println("compare start");synchronized (this) {for (int i = 0; i < 10000; i++) {boolean flag = a < b;if (flag) {System.out.println("a=" + a + ",b=" + b + "flag=" + flag + ",a < b = " + (a < b));}}}System.out.println("compare end");}public static void main(String[] args) {SynchronizedTest2 synchronizedTest = new SynchronizedTest2();new Thread(() -> synchronizedTest.add()).start();new Thread(() -> synchronizedTest.compare()).start();}
}
为了更好的优化,有的时候可以将synchronized代码块变为区分读写场景的读写锁,也可以考虑悲观锁和乐观锁的区分。
对于读写场景比较多的情况,可以使用ReentrantReadWriteLock区分读写,再次降低锁的粒度,提高程序的性能。
ReentrantReadWriteLock 还可以选择提供了公平锁,在没有明确必须使用公平锁的情况下,尽量不要使用公平锁,公平锁会使程序性能降低很多很多。
二、先区分一下公平锁和非公平锁
- 公平锁:多个线程按照申请锁的顺序去获得锁,线程会直接进入队列去排队,永远都是队列的第一个得到锁。
- 非公平锁:多个线程去获取锁的时候,会直接去尝试获取,获取不到,进入等待队列,如果能获取到,就直接获取到锁。
简单来说,公平锁(谁先排队,谁先执行),非公平锁(不用排队,每个人都有机会)。
1、公平锁
有一天早上,云韵、美杜莎、小医仙结伴去买酱香拿铁,到了咖啡店,先排队,一个一个来。不一会,哪吒来了,也买酱香拿铁,只能在末尾排队。这个就是公平锁。
2、非公平锁
但是呢?第二天早上,哪吒又去买酱香拿铁,上一次去晚了没买到(线程被饿死了),这次急了,要插队买,不讲武德。终于喝上了心心念念的酱香拿铁,这个就是非公平锁。
3、公平锁的优缺点:
- 优点:所有线程都会获取到锁,只是一个时间的问题,不会出现有线程被饿死的情况;
- 缺点:吞吐量会下降很多,队列里只有第一个线程能获取到锁,其他的线程都会阻塞,cpu唤醒阻塞线程的开销会增大。
4、非公平锁的优缺点:
- 优点:可以减少CPU唤醒线程的开销,整体的吞吐效率会高点,CPU也不必取唤醒所有线程,会减少唤起线程的数量。
- 缺点:如果运气不好,会出现一致获取不到锁的情况,会被活活的饿死。
三、是否对症下药
我们都知道,静态字段属于类,类级别的锁才能保护;非静态字段属于类实例,实例级别的锁才能保护。
先看一下下面的代码:
import lombok.Data;import java.util.stream.IntStream;@Data
public class LockTest {public static void main(String[] args) {IntStream.rangeClosed(1, 100000).parallel().forEach(i -> new LockTest().increase());System.out.println(time);}private static int time = 0;public synchronized void increase() {time++;}
}
在LockTest类中定义一个静态变量time,定义一个非静态方法increase(),实现time++自增。先累加10万次,测试一下。看看是否有线程安全的问题。
这…不对啊,上一节在介绍高并发下i++线程安全问题的时候,synchronized 是好使的啊。
今天这是怎么了?再运行一次,结果依然如此,不等于100000
先来分析一下。
在非静态的方法上加synchronized,只能确保多个线程无法执行同一个实例的increase()方法,却不能保证不同实例的increase()方法。
静态的变量time,在多个线程中共享,所以会出现线程安全的问题,synchronized失效了。
那么,将synchronized改为静态方法是不是就可以了,试一下。
有两种写法,一种是直接将方法改为静态方法,一种是使用synchronized代码块。
private static Object obj= new Object();
public void increase() {synchronized (obj) {time++;}
}
四、IntStream.rangeClosed是干嘛的?
很多小伙伴,可能会好奇,这个是干什么的,干了5年后端代码开发了,没见过这玩意儿。
IntStream是一种特殊的stream,用来提供对int相关的stream操作。
IntStream.rangeClosed:生成某个数字范围内的数字集合的stream。
比如上面代码中的IntStream.rangeClosed(1, 100000).parallel().forEach(i -> new LockTest().increase());
。
- range:不包含10000
- rangeClosed:包含10000
关于Java8 新特性 Stream流的详细介绍,可以看一下这个【Java8 新特性 5】Java 8 stream的详细用法。
五、parallel是干嘛的?
1、parallel()是什么
Stream.parallel() 方法是 Java 8 中 Stream API 提供的一种并行处理方式。在处理大量数据或者耗时操作时,使用 Stream.parallel() 方法可以充分利用多核 CPU 的优势,提高程序的性能。
Stream.parallel() 方法是将串行流转化为并行流的方法。通过该方法可以将大量数据划分为多个子任务交由多个线程并行处理,最终将各个子任务的计算结果合并得到最终结果。使用 Stream.parallel() 可以简化多线程编程,减少开发难度。
需要注意的是,并行处理可能会引入线程安全等问题,需要根据具体情况进行选择。
2、举一个简单的demo
定义一个list,然后通过parallel() 方法将集合转化为并行流,对每个元素进行i++,最后通过 collect(Collectors.toList()) 方法将结果转化为 List 集合。
使用并行处理可以充分利用多核 CPU 的优势,加快处理速度。
public class StreamTest {public static void main(String[] args) {List<Integer> list = new ArrayList<>();for (int i = 0; i < 10; i++) {list.add(i);}System.out.println(list);List<Integer> result = list.stream().parallel().map(i -> i++).collect(Collectors.toList());System.out.println(result);}
}
我勒个去,什么情况?
这是大部分开发人员都会犯的小错误,在上篇中提到过,i++ 返回原来的值,++i 返回加1后的值
。这谁都知道,可是,写的时候,就不一定了,因为你习惯了i++,写顺手了,写的时候也是心不在焉,一蹴而就了。
i++改了++i即可。
3、parallel()的优缺点
(1)优点:
- 充分利用多核 CPU 的优势,提高程序的性能;
- 可以简化多线程编程,减少开发难度。
(2)缺点:
- 并行处理可能会引入线程安全等问题,需要根据具体情况进行选择;
- 并行处理需要付出额外的开销,例如线程池的创建和销毁、线程切换等,对于小数据量和简单计算而言,串行处理可能更快。
4、何时使用parallel()?
在实际开发中,应该根据数据量、计算复杂度、硬件等因素综合考虑。
比如:
- 数据量较大,有1万个元素;
- 计算复杂度过大,需要对每个元素进行复杂的计算;
- 硬件够硬,比如多核CPU。
上一篇:一个关于 i++ 和 ++i 的面试题打趴了所有人
🏆哪吒多年工作总结:Java学习路线总结,搬砖工逆袭Java架构师。
相关文章:

简单聊一聊公平锁和非公平锁,parallel并行流
目录 一、降低锁的粒度,将synchronized关键字不放在方法上了,改为synchronized代码块。二、先区分一下公平锁和非公平锁1、公平锁2、非公平锁3、公平锁的优缺点:4、非公平锁的优缺点: 三、是否对症下药四、IntStream.rangeClosed是…...

【SpringCloud】微服务技术栈入门4 - RabbitMQ初探
目录 RabbitMQ安装 rabbitmqSpringAMQP 基础队列WorkQueue路由发布订阅 FanoutExchangeDirectExchangeTopicExchange RabbitMQ 安装 rabbitmq 首先确保自己已经安装好了 docker 是 docker 拉取镜像文件:docker pull rabbitmq:3-management 拉取完毕,打…...
cefsharp(117.2.20)cef117.2.2最新体验版
一、下载nupkg https://www.nuget.org/packages/CefSharp.WinForms/ https://www.nuget.org/packages/CefSharp.Common/ https://www.nuget.org/packages/cef.redist.x64/ https://www.nuget.org/packages/cef.redist.x86/ 此版本暂时不支持H264。上一版本支持H264 cefsharp…...
layui在上传图片在前端处理图片压缩
有的人会遇到需要在前端代码处理图片压缩的问题,下面给大家分享怎么处理。 // 上传图片 var image_src var IsImgDealfalse; layui.upload.render({ elem: "#{tag}{id}", url: sessionStorage.getItem(httpUrlPrefix) /upload/uploadImage, // dataT…...

js 事件参考
事件参考 事件介绍 触发事件是为了通知代码可能影响代码执行的“有趣变化”。这些可能来自用户交互,例如使用鼠标或调整窗口大小,底层环境状态的变化(例如,低电量或来自操作系统的媒体事件)以及其他原因。 每个事件都由一个基于Event接口的…...

卷积网络的发展历史-LeNet
简介 LeNet是CNN结构的开山鼻祖,第一次定义了卷积神经网络的结构。 LeNet模型包含了多个卷积层和池化层,以及最后的全连接层用于分类。其中,每个卷积层都包含了一个卷积操作和一个非线性激活函数,用于提取输入图像的特征。池化层…...

(2023,GPT-4V,LLM,LMM,功能和应用)大型多模态模型的黎明:GPT-4V(ision) 的初步探索
The Dawn of LMMs: Preliminary Explorations with GPT-4V(ision) 公众号:EDPJ(添加 VX:CV_EDPJ 或直接进 Q 交流群:922230617 获取资料) 目录 0. 摘要 1. 简介 1.1 动机和概述 1.2 我们探索 GPT-4V 的方法 1.3…...

【C++设计模式之装饰模式:结构型】分析及示例
装饰模式(Decorator Pattern)是一种结构型设计模式,它允许在运行时动态地给一个对象添加额外的行为。 描述 装饰模式通过创建一个包装器(Wrapper)来包裹原始对象,并在原始对象的行为前后添加额外的功能。…...
绘制散点图、曲线图、折线图和环形图失败, 设置迭代次数和进度无法保存图片
错误❌ 分别input设置(我想知道微积分的力量) 设1个人,他有每天3种方案,每天进步千分之一,千分之一,十万分之一等到他们迭代 200,500,1000,2000,3000,5000,9000次 他们在图片什么位置画曲线图࿰…...

micro-ROS中对消息的内存管理
文章目录 1.背景2.答案2.1.基本类型及其数组,不需要2.1.序列类型(复合类型、复合序列类型),需要 3.内存申请方法3.1.手动申请(Manual allocation)3.1.工具辅助(micro-ROS utilities)…...

Springboot中使用拦截器、过滤器、监听器
一、Servlet、Filter(过滤器)、 Listener(监听器)、Interceptor(拦截器) Javaweb三大组件:servlet、Filter(过滤器)、 Listener(监听器) Spring…...
代码随想录二刷day45
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、力扣70. 爬楼梯二、力扣322. 零钱兑换三、力扣279. 完全平方数 前言 一、力扣70. 爬楼梯 class Solution {public int climbStairs(int n) {int[] dp new…...

泊车功能专题介绍 ———— AVP系统基础数据交互内容
文章目录 系统架构系统功能描述云端子系统车辆子系统场端子系统用户APP 工作流程基础数据交互内容AVP 系统基础数据交互服务车/用户 - 云基础数据交互内容车位查询工作流程技术要求数据交互要求 车位预约工作流程技术要求数据交互要求 取消预约工作流程技术要求数据交互要求 泊…...

蓝桥杯每日一题2023.10.6
题目描述 门牌制作 - 蓝桥云课 (lanqiao.cn) 题目分析 #include<bits/stdc.h> using namespace std; int ans; int main() {for(int i 1; i < 2020; i ){int x i;while(x){int a x % 10;if(a 2)ans ;x / 10;}}cout << ans;return 0; } 题目描述 既约分数…...
7、【Qlib】【主要组件】Data Layer:数据框架与使用
7、【主要组件】Data Layer:数据框架与使用 简介数据准备Qlib 格式数据Qlib 格式数据集自动更新日频率数据将 CSV 格式转换为 Qlib 格式股票池(市场)多股票模式 数据API数据检索特征过滤器 数据加载器QlibDataLoaderStaticDataLoaderInterfac…...

Kubernetes安装部署 1
本文主要描述kubernetes的安装部署,kubernetes的安装部署主要包括三个关键组件,其中,包括kubeadm、kubelet、kubectl,这三个组件的功能描述如下所示: Kubeadm 用于启动与管理kubernetes集群 Kubelet 运行在所有集群的…...

在VS Code中优雅地编辑csv文件
文章目录 Rainbow csv转表格CSV to Tablecsv2tableCSV to Markdown Table Edit csv 下面这些插件对csv/tsv/psv都有着不错的支持,这几种格式的主要区别是分隔符不同。 功能入口/使用方法Rainbow csv按列赋色右键菜单CSV to Table转为ASCII表格指令CSV to Markdown …...
LCR 128.库存管理 I
题目来源: leetcode题目,网址:LCR 128. 库存管理 I - 力扣(LeetCode) 解题思路: 数组可以分割成两段的升序连续子数组,找到两个子数组的开始元素并返回较小者即可。 解题代码: …...
eigen::Affine3d 转换
平移eigen::vector3d和四元数Eigen::Quaterniond 转 eigen::Affine3d Eigen::Vector3d t Eigen::Vector3d::Zero(); Eigen::Quaterniond q Eigen::Quaterniond ::Identity();Eigen::Affine3d affine3d t * q.toRotationMatrix(); Eigen::Matrix4d 转 eigen::Affine3d Eige…...

【Python从入门到进阶】38、selenium关于Chrome handless的基本使用
接上篇《37、selenium关于phantomjs的基本使用》 上一篇我们介绍了有关phantomjs的相关知识,但由于selenium已经放弃PhantomJS,本篇我们来学习Chrome的无头版浏览器Chrome Handless的使用。 一、Chrome Headless简介 Chrome Headless是一个无界面的浏览…...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...
React 第五十五节 Router 中 useAsyncError的使用详解
前言 useAsyncError 是 React Router v6.4 引入的一个钩子,用于处理异步操作(如数据加载)中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误:捕获在 loader 或 action 中发生的异步错误替…...
HTML 语义化
目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案: 语义化标签: <header>:页头<nav>:导航<main>:主要内容<article>&#x…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...
LangFlow技术架构分析
🔧 LangFlow 的可视化技术栈 前端节点编辑器 底层框架:基于 (一个现代化的 React 节点绘图库) 功能: 拖拽式构建 LangGraph 状态机 实时连线定义节点依赖关系 可视化调试循环和分支逻辑 与 LangGraph 的深…...

Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement
Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement 1. LAB环境2. L2公告策略2.1 部署Death Star2.2 访问服务2.3 部署L2公告策略2.4 服务宣告 3. 可视化 ARP 流量3.1 部署新服务3.2 准备可视化3.3 再次请求 4. 自动IPAM4.1 IPAM Pool4.2 …...

C++--string的模拟实现
一,引言 string的模拟实现是只对string对象中给的主要功能经行模拟实现,其目的是加强对string的底层了解,以便于在以后的学习或者工作中更加熟练的使用string。本文中的代码仅供参考并不唯一。 二,默认成员函数 string主要有三个成员变量,…...
拟合问题处理
在机器学习中,核心任务通常围绕模型训练和性能提升展开,但你提到的 “优化训练数据解决过拟合” 和 “提升泛化性能解决欠拟合” 需要结合更准确的概念进行梳理。以下是对机器学习核心任务的系统复习和修正: 一、机器学习的核心任务框架 机…...

Linux入门(十五)安装java安装tomcat安装dotnet安装mysql
安装java yum install java-17-openjdk-devel查找安装地址 update-alternatives --config java设置环境变量 vi /etc/profile #在文档后面追加 JAVA_HOME"通过查找安装地址命令显示的路径" #注意一定要加$PATH不然路径就只剩下新加的路径了,系统很多命…...

信息收集:从图像元数据(隐藏信息收集)到用户身份的揭秘 --- 7000
目录 🌐 访问Web服务 💻 分析源代码 ⬇️ 下载图片并保留元数据 🔍 提取元数据(重点) 👤 生成用户名列表 🛠️ 技术原理 图片元数据(EXIF 数据) Username-Anarch…...