第18章 不可变对象设计模式(Java高并发编程详解:多线程与系统设计)
1.线程安全
所谓共享的资源,是指在多个线程同时对其进行访问的情况下,各线程都会使其发生变化,而线程安全性的主要目的就在于在受控的并发访问中防止数据发生变化。除了使用synchronized关键字同步对资源的写操作之外, 还可以在线程之间不共享资源状态, 甚至将资源的状态设置为不可变。在本章中,我们将讨论如何设计不可变对象,这样就可以不用依赖于synchronized关键字的约束。
2.不可变对象的设计
Java核心类库中提供了大量的不可变对象范例, 其中java.lang.String的每一个方法都没有同步修饰, 可是其在多线程访问的情况下是安全的, Java 8中通过Stream修饰的ArrayList在函数式方法并行访问的情况下也是线程安全的, 所谓不可变对象是没有机会去修改它, 每一次的修改都会导致一个新的对象产生, 比如Strings 1=“Hello”;sl=s1+” world”两者相加会产生新的字符串。
有些非线程安全可变对象被不可变机制加以处理之后,照样也具备不可变性,比如ArrayList生成的stream在多线程的情况下也是线程安全的, 同样是因为其具备不可变性的结果,示例代码所示。
import java.util.Arrays;
import java.util.List;public class ArrayListStream {public static void main(String[] args) {// 定义一个list并且使用Arrays的方式进行初始化List<String> list = Arrays.asList("Java","Thread", "Concurrency","Scala","Co");// 获取并行的stream,然后通过map函数对list中的数据进行加工,最后输出list.parallelStream().map(String::toUpperCase).forEach(System.out::println);list.forEach(System.out::println);}
}
2.1 非线程安全的累加器
不可变对象最核心的地方在于不给外部修改共享资源的机会,这样就会避免多线程情况下的数据冲突而导致的数据不一致的情况,又能避免因为对锁的依赖而带来的性能降低,好了, 在本节中我们将模仿java.lang.String的方式实现一个不可变的int类型累加器, 先来看看不加同步的累加器,代码如所示。
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;public class IntegerAccumulator {private int init;public IntegerAccumulator(int init) {this.init = init;}public int add(int i ) {this.init += i;return this.init;}public int getValue() {return this.init;}public static void main(String[] args) {// 定义累加器,并且设计初始值为0IntegerAccumulator accumulator = new IntegerAccumulator(0);// 定义三个线程,并且分别启动IntStream.range(0,3).forEach(i->new Thread(() -> {int inc = 0;while(true) {//int oldvalue = accumulator.getValue();int result = accumulator.add(inc);System.out.println("result:" + result);if(inc + oldvalue != result ) {System.out.println("ERROR:" + oldvalue + "+" + inc + "=" + result);}inc++;slowly();}}).start());}// 简单模拟操作的耗时private static void slowly() {try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}}
}
2.2 方法同步增加线程安全性
2.3 不可变的累加器对象设计
2.2节中通过同步的方式解决了线程安全性的问题,正确的加锁方式固然能使得一个类变成线程安全的, 比如java.utils.Vector, 但是我们需要的是设计出类似于java.lang.String的不可变类,示例代码如所示。
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;public class IntegerAccumulator1 {private int init;public IntegerAccumulator1(int init) {this.init = init;}// 构造新的累加器,需要用到另一个累加public IntegerAccumulator1(IntegerAccumulator1 integerAccumulator, int init) {this.init = integerAccumulator.getValue() + init;}// public int add(int i ) {
// this.init += i;
// return this.init;
// }public IntegerAccumulator1 add(int init) {return new IntegerAccumulator1(this, init);}public int getValue() {return this.init;}public static void main(String[] args) {// 定义累加器,并且设计初始值为0IntegerAccumulator1 accumulator = new IntegerAccumulator1(0);// 定义三个线程,并且分别启动IntStream.range(0,3).forEach(i->new Thread(() -> {int inc = 0;while(true) {//int oldvalue = accumulator.getValue();int result = accumulator.add(inc).getValue();System.out.println("result:" + result);if(inc + oldvalue != result ) {System.out.println("ERROR:" + oldvalue + "+" + inc + "=" + result);}inc++;slowly();}}).start());}// 简单模拟操作的耗时private static void slowly() {try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}}
}
重构后的Integer Accumulator, 使用了final修饰其的目的是为了防止由于继承重写而导致失去线程安全性, 另外init属性被final修饰不允许线程对其进行改变, 在构造函数中赋值后将不会再改变。
add方法并未在原有in it的基础之上进行累加, 而是创建了一个全新的IntegerAccumulator, 并未提供任何修改原始IntegerAccumulator的机会,运行上面的程序不会出现ERROR的情况。
相关文章:
第18章 不可变对象设计模式(Java高并发编程详解:多线程与系统设计)
1.线程安全 所谓共享的资源,是指在多个线程同时对其进行访问的情况下,各线程都会使其发生变化,而线程安全性的主要目的就在于在受控的并发访问中防止数据发生变化。除了使用synchronized关键字同步对资源的写操作之外, 还可以在线…...
openEuler22.03LTS系统升级docker至26.1.4以支持启用ip6tables功能
本文记录了openEuler22.03LTS将docker升级由18.09.0升级至26.1.4的过程(当前docker最新版本为27.5.1,生产环境为保障稳定性,选择升级到上一个大版本26的最新小版本)。 一、现有环境 1、系统版本 [rootlocalhost opt]# cat /etc…...
< OS 有关 > Ubuntu 版本升级 实践 24.04 -> 24.10, 安装 .NET
原因: 想安装 .NET 9 去编译 GitHut 项目,这回用不熟悉的 Ubuntu来做,不知道怎么拐去给 Ubuntu 升级,看到现在版本是 24.10 但不是 LTS 版本,记录下升级过程。 一、实践过程: 1. 查看当前版本 命令1: l…...
某咨询大数据解决方案介绍(32页PPT)
本文档介绍了一个大数据平台解决方案,旨在解决企业当前面临的数据问题,包括数据定义缺失、重复采集和存储、数据不完整以及缺乏可靠决策依据等。通过引入大数据技术,该方案强调从被动的IT支撑向主动的数据核心服务转型,以实现科学…...
ZooKeeper作为注册中心有什么问题? ZooKeeper作为注册中心,海量服务同时重启有什么问题?
目录 ZooKeeper作为注册中心存在的问题 性能瓶颈 一致性保证 复杂性 扩展性 单点故障 数据模型限制 社区和生态 安全性 总结 ZooKeeper作为注册中心,海量服务同时重启有的问题 1. ZooKeeper集群压力剧增 2. ZooKeeper Leader节点压力 3. 会话和临时节点管理 4.…...
matlab simulink 汽车四分之一模型主动被动悬架-LQR
1、内容简介 略 matlab simulink 可以交流、咨询、答疑 124- 2、内容说明 略汽车悬架系统由弹性元件、导向元件和减振器组成,是车身与车轴之间连接的所有组合体零件的总称,也是车架(或承载式车身)与车桥(或车轮)之间一切力传递装置的总称,其主要功能是使车轮与地面有很好的…...
从零开始:OpenCV 图像处理快速入门教程
文章大纲 第1章 OpenCV 概述 1.1 OpenCV的模块与功能 1.2 OpenCV的发展 1.3 OpenCV的应用 第2章 基本数据类型 2.1 cv::Vec类 2.2 cv::Point类 2.3 cv::Rng类 2.4 cv::Size类 2.5 cv:&…...
基础相对薄弱怎么考研
复习总体规划 明确目标 选择专业和院校:根据你的兴趣、职业规划和自身实力,选择适合自己的专业和院校。可以参考往年的分数线、报录比、复试难度等。了解考试科目:不同专业考试科目不同,一般包括: 公共课:…...
强化学习笔记6——异同策略、AC、等其他模型总结
异步两种方法:1:经验回放 2:数据动作非同时产生 举例QLearning为什么是异策略? 生成动作时e的概率从Q表选,1-e概况随机。 更新策略时,贪心策略选择Q_max作为动作。 策略优化两种主要方法:基于梯…...
Linux提权--passwd提权
passwd 命令用于更改用户密码。在 Linux 系统中,普通用户可以通过 passwd 更改自己的密码,但如果攻击者能够以某种方式执行 passwd 命令更改 root 用户的密码,他们就能获取 root 权限。 1.常见的 passwd 提权方法 SUID 设置࿱…...
一、本地部署安装 DeepSeek 并训练本地知识库,并调用对话框进行问答
本地部署安装 DeepSeek 1、硬件环境 操作系统:Windows10 内存:16G 显卡:NIVIDIA GeForce RTX 2060 6G 2、安装步骤 (1)安装 Ollama 访问Ollama 官网,点击 “Download for Windows” 下载安装程序。下载…...
海思的一站式集成环境Hispark Studio更新了
HiSpark Studio是海思提供的面向智能设备开发者提供一站式集成开发环境,支持代码编辑、编译、烧录和调试等功能。我以前在评测星闪芯片的时候用过,当时写了篇博客:【星闪开发连载】WS63E开发板Windows环境的构建_hispark studio-CSDN博客。那…...
从零开始构建强大 AI 对话系统:ollama + deepseek + open-webui 完整部署教程(Docker 版)
文章目录 前言一、工具简介二、前期准备三、部署步骤1. 安装并配置 ollama2. 部署 open-webui 四、调试与验证五、Docker Compose 简化部署六、注意事项与常见问题1. ollama run 500 报错2. 硬件配置对性能的影响3. **ollama** 启动与 **open-webui** 调用速度差异4. 内存不足导…...
unity学习29:摄像机camera相关skybox 和 Render Texture测试效果
目录 1 摄像机 1.1 每个Scene里都自带一个摄像机 camera 1.2 可以创建多个camera 1.3 下面先看backgroundtype: 2 backgroundtype: 天空盒 skybox 2.1 清除标志,清除:天空盒 自选天空盒 2.2 window /Asset Store 2.3 导入skybox 3 backgroundtype: 纯色…...
【Elasticsearch】Geo-distance聚合
geo_distance聚合的形状是圆形。它基于一个中心点(origin)和一系列距离范围来计算每个文档与中心点的距离,并将文档分配到相应的距离范围内。这种聚合方式本质上是以中心点为圆心,以指定的距离范围为半径的圆形区域来划分数据。 为…...
音频进阶学习十二——Z变换
文章目录 前言一、Z变换1.Z变换的作用2.Z变换公式3.Z的状态表示1) r 1 r1 r12) 0 < r < 1 0<r<1 0<r<13) r > 1 r>1 r>1 4.关于Z的解释 二、收敛域1.收敛域的定义2.收敛域的表示方式3.ROC的分析1)当 …...
easyxor
easyxor 一、查壳 无壳,64位 二、IDA分析 1.main 2.查看key与r(shifee提取) 三、脚本 r [0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, …...
通过多层混合MTL结构提升股票市场预测的准确性,R²最高为0.98
“Boosting the Accuracy of Stock Market Prediction via Multi-Layer Hybrid MTL Structure” 论文地址:https://arxiv.org/pdf/2501.09760 摘要 本研究引入了一种创新的多层次混合多任务学习架构,致力于提升股市预测的效能。此架构融…...
日本游戏机市场5年来首次陷入萎缩;特斯拉招人推进人形机器人量产;任天堂专利显示Switch2手柄可用作鼠标...| 游戏智眼日报
美团成立“算法顾问委员会” 美团宣布,近日,由外部专家学者组成的算法顾问委员会成立,为美团改进算法提供常态化咨询和指导。每个季度美团将举办算法恳谈会,持续邀请骑手、商家、用户、专家学者和媒体代表等共同参加。美团表示&a…...
114-机器学习分类算法
1、内容简介 略 matlab simulink 114-机器学习分类算法可以交流、咨询、答疑 2、内容说明 略 Elong_6.24。ROCAUC confusion newdata Unbalanced_LR.car 3、仿真分析 略 4、参考论文 略...
【论文阅读】On the Security of “VOSA“
On the Security of Verifiable and Oblivious Secure Aggregation for Privacy-Preserving Federated Learning -- 关于隐私保护联邦中可验证与遗忘的安全聚合的安全性 论文来源摘要Introduction回顾 VOSA 方案对VOSA不可伪造性的攻击对于类型 I 的攻击对于类型 II 的攻击 论文…...
12.6 LangChain检索器(Retrievers)全解析:构建高效RAG应用的核心引擎
LangChain检索器(Retrievers)全解析:构建高效RAG应用的核心引擎 一、检索器的核心价值 检索器是大模型应用的智能导航系统,通过将用户查询与知识库精准匹配,解决了传统搜索的三大痛点: 语义鸿沟:突破关键词匹配,理解用户真实意图多源整合:融合向量搜索、关键词搜索和…...
707设计链表(链表操作)
1、题目描述 你可以选择使用单链表或者双链表,设计并实现自己的链表。 单链表中的节点应该具备两个属性:val 和 next 。val 是当前节点的值,next 是指向下一个节点的指针/引用。 如果是双向链表,则还需要属性 prev 以指示链表中…...
储能系统-系统架构
已更新系列文章包括104、61850、modbus 、单片机等,欢迎关注 IEC61850实现方案和测试-1-CSDN博客 快速了解104协议-CSDN博客 104调试工具2_104协议调试工具-CSDN博客 1 电池储能系统(BESS) 架构 电池储能系统主要包括、电池、pcs、本地控制…...
Spring Boot 需要独立的容器运行吗
Spring Boot 不需要独立的容器运行,它内置了一个嵌入式的Web服务器(如Tomcat、Jetty或Undertow),所以可以直接作为一个独立的应用程序运行,而不需要外部的Servlet容器。你只需要运行Spring Boot应用,它会自…...
Spring Security在java中的详细用处///为什么用了jwt之后就不能用session
Spring Security 是一个功能强大且高度可定制的认证和授权框架,主要用于基于 Spring 的应用程序中。它不仅处理 HTTP 请求的安全性(包括认证和授权),还提供了其他安全相关的特性如防止 CSRF 攻击、会话管理、安全头信息设置等。以…...
Ubuntu系统 Zabbix 7.2LTS一键部署脚本
为了在 Ubuntu 系统上快速部署 Zabbix 7.2 LTS 版本,您可以使用一个自动化 Bash 脚本来简化安装过程。以下是一个适用于 Ubuntu 系统的 Zabbix 7.2 LTS 一键部署脚本。此脚本将安装 Zabbix Server、Zabbix Web 界面(基于 Nginx 和 PHP)以及 Z…...
基于HTML、CSS 和 JavaScript 开发个人读书类网站
以下是一个使用 HTML、CSS 和 JavaScript 开发个人读书类网站的示例代码,包含基本功能和样式: 我的读书空间 我的书库 首页 添加新书 <div class="container"><!-- 首页内容 --><div id="home"><h2>当前阅读列表</h2><…...
Ollama python交互:chat+embedding实践
Ollama简介 Ollama 是一个开源的大型语言模型(LLM)平台,旨在让用户能够轻松地在本地运行、管理和与大型语言模型进行交互。 Ollama 提供了一个简单的方式来加载和使用各种预训练的语言模型,支持文本生成、翻译、代码编写、问答等…...
安卓路由与aop 以及 Router-api
安卓路由(Android Router)和AOP(面向切面编程)是两个在Android开发中常用的概念。下面我将详细讲解这两个概念及其在Android开发中的应用。 一、安卓路由 安卓路由主要用于在应用程序中管理不同组件之间的导航和通信。它可以简化…...
