第18章 不可变对象设计模式(Java高并发编程详解:多线程与系统设计)

news2025/2/8 5:56:00

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) {
        // 定义累加器,并且设计初始值为0
        IntegerAccumulator 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) {
        // 定义累加器,并且设计初始值为0
        IntegerAccumulator1 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的情况。

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

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

相关文章

openEuler22.03LTS系统升级docker至26.1.4以支持启用ip6tables功能

本文记录了openEuler22.03LTS将docker升级由18.09.0升级至26.1.4的过程&#xff08;当前docker最新版本为27.5.1&#xff0c;生产环境为保障稳定性&#xff0c;选择升级到上一个大版本26的最新小版本&#xff09;。 一、现有环境 1、系统版本 [rootlocalhost opt]# cat /etc…

< OS 有关 > Ubuntu 版本升级 实践 24.04 -> 24.10, 安装 .NET

原因&#xff1a; 想安装 .NET 9 去编译 GitHut 项目&#xff0c;这回用不熟悉的 Ubuntu来做&#xff0c;不知道怎么拐去给 Ubuntu 升级&#xff0c;看到现在版本是 24.10 但不是 LTS 版本&#xff0c;记录下升级过程。 一、实践过程&#xff1a; 1. 查看当前版本 命令1: l…

某咨询大数据解决方案介绍(32页PPT)

本文档介绍了一个大数据平台解决方案&#xff0c;旨在解决企业当前面临的数据问题&#xff0c;包括数据定义缺失、重复采集和存储、数据不完整以及缺乏可靠决策依据等。通过引入大数据技术&#xff0c;该方案强调从被动的IT支撑向主动的数据核心服务转型&#xff0c;以实现科学…

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&#xff1a;&#xff1a;Point类 2.3 cv&#xff1a;&#xff1a;Rng类 2.4 cv&#xff1a;&#xff1a;Size类 2.5 cv&#xff1a;&…

强化学习笔记6——异同策略、AC、等其他模型总结

异步两种方法&#xff1a;1&#xff1a;经验回放 2&#xff1a;数据动作非同时产生 举例QLearning为什么是异策略&#xff1f; 生成动作时e的概率从Q表选&#xff0c;1-e概况随机。 更新策略时&#xff0c;贪心策略选择Q_max作为动作。 策略优化两种主要方法&#xff1a;基于梯…

Linux提权--passwd提权

passwd​ 命令用于更改用户密码。在 Linux 系统中&#xff0c;普通用户可以通过 passwd​ 更改自己的密码&#xff0c;但如果攻击者能够以某种方式执行 passwd​ 命令更改 root 用户的密码&#xff0c;他们就能获取 root 权限。 1.常见的 passwd 提权方法 SUID 设置&#xff1…

一、本地部署安装 DeepSeek 并训练本地知识库,并调用对话框进行问答

本地部署安装 DeepSeek 1、硬件环境 操作系统&#xff1a;Windows10 内存&#xff1a;16G 显卡&#xff1a;NIVIDIA GeForce RTX 2060 6G 2、安装步骤 &#xff08;1&#xff09;安装 Ollama 访问Ollama 官网&#xff0c;点击 “Download for Windows” 下载安装程序。下载…

海思的一站式集成环境Hispark Studio更新了

HiSpark Studio是海思提供的面向智能设备开发者提供一站式集成开发环境&#xff0c;支持代码编辑、编译、烧录和调试等功能。我以前在评测星闪芯片的时候用过&#xff0c;当时写了篇博客&#xff1a;【星闪开发连载】WS63E开发板Windows环境的构建_hispark studio-CSDN博客。那…

unity学习29:摄像机camera相关skybox 和 Render Texture测试效果

目录 1 摄像机 1.1 每个Scene里都自带一个摄像机 camera 1.2 可以创建多个camera 1.3 下面先看backgroundtype: 2 backgroundtype: 天空盒 skybox 2.1 清除标志,清除&#xff1a;天空盒 自选天空盒 2.2 window /Asset Store 2.3 导入skybox 3 backgroundtype: 纯色…

【Elasticsearch】Geo-distance聚合

geo_distance聚合的形状是圆形。它基于一个中心点&#xff08;origin&#xff09;和一系列距离范围来计算每个文档与中心点的距离&#xff0c;并将文档分配到相应的距离范围内。这种聚合方式本质上是以中心点为圆心&#xff0c;以指定的距离范围为半径的圆形区域来划分数据。 为…

音频进阶学习十二——Z变换

文章目录 前言一、Z变换1.Z变换的作用2.Z变换公式3.Z的状态表示1&#xff09; r 1 r1 r12&#xff09; 0 < r < 1 0<r<1 0<r<13&#xff09; r > 1 r>1 r>1 4.关于Z的解释 二、收敛域1.收敛域的定义2.收敛域的表示方式3.ROC的分析1&#xff09;当 …

easyxor

easyxor 一、查壳 无壳&#xff0c;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” 论文地址&#xff1a;https://arxiv.org/pdf/2501.09760 ​​​​​​​ 摘要 本研究引入了一种创新的多层次混合多任务学习架构&#xff0c;致力于提升股市预测的效能。此架构融…

日本游戏机市场5年来首次陷入萎缩;特斯拉招人推进人形机器人量产;任天堂专利显示Switch2手柄可用作鼠标...| 游戏智眼日报

美团成立“算法顾问委员会” 美团宣布&#xff0c;近日&#xff0c;由外部专家学者组成的算法顾问委员会成立&#xff0c;为美团改进算法提供常态化咨询和指导。每个季度美团将举办算法恳谈会&#xff0c;持续邀请骑手、商家、用户、专家学者和媒体代表等共同参加。美团表示&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 的攻击 论文…

储能系统-系统架构

已更新系列文章包括104、61850、modbus 、单片机等&#xff0c;欢迎关注 IEC61850实现方案和测试-1-CSDN博客 快速了解104协议-CSDN博客 104调试工具2_104协议调试工具-CSDN博客 1 电池储能系统&#xff08;BESS&#xff09; 架构 电池储能系统主要包括、电池、pcs、本地控制…

ip属地是手机号还是手机位置?一文理清

在数字化和网络化的今天&#xff0c;IP属地这一概念逐渐成为了人们关注的焦点。特别是在社交媒体和在线平台上&#xff0c;IP属地的显示往往让人联想到用户的地理位置。然而&#xff0c;关于IP属地到底与手机号还是手机位置有关&#xff0c;却存在着不少误解和混淆。本文将深入…

迅为RK3568开发板篇OpenHarmony实操HDF驱动控制LED-编写应用APP

在应用代码中我们实现如下功能&#xff1a; 当应用程序启动后会获取命令行参数。如果命令行没有参数&#xff0c;LED 灯将循环闪烁&#xff1b;如果命令行带有参数&#xff0c;则根据传输的参数控制 LED 灯的开启或关闭。通过 HdfIoServiceBind 绑定 LED灯的 HDF 服务&#xff…