当前位置: 首页 > news >正文

JAVA高并发——单例模式和不变模式

文章目录

  • 1、探讨单例模式
  • 2、不变模式

由于并行程序设计比串行程序设计复杂得多,因此我强烈建议大家了解一些常见的设计方法。就好像练习武术,一招一式都是要经过学习的。如果自己胡乱打,效果不见得好。前人会总结一些武术套路,对于初学者来说,不需要发挥自己的想象力,只要按照武术套路出拳就可以了。等练到了一定的程度,就不必拘泥于套路了。这些武术套路和招数,对应到软件开发中就是设计模式。在这里,我将重点向大家介绍一些并行模式与算法。这些都是前人的经验总结,大家可以在熟知其思想和原理的基础上,再根据自己的需求进行扩展,可能会达到更好的效果。

1、探讨单例模式

单例模式是设计模式中使用最普遍的模式之一。它是一种对象创建模式,用于产生一个对象的具体实例,它可以确保系统中一个类只产生一个实例。在Java中,这样的行为能带来两大好处:

  • (1)对于频繁使用的对象,可以省略new操作花费的时间,这对于那些重量级对象而言,是非常可观的一笔系统开销。
  • (2)由于new操作的次数减少,对系统内存的使用频率也会降低,这将减轻GC的压力,缩短GC停顿时间。

严格来说,单例模式与并行模式没有直接的关系。讨论这个模式,是因为它实在是太常见了,我们不可避免地会在多线程环境中使用它们。并且,系统中使用单例的地方可能非常多,因此我们非常迫切地需要一种高效的单例实现。

下面给出了一个单例的实现,这个实现是非常简单的,是一个正确并且良好的实现:
在这里插入图片描述
使用以上方式创建单例时有几点必须特别注意。因为我们要保证系统中不会有人意外创建多余的实例,所以我们把Singleton的构造函数设置为私有的。这非常重要,这就警告所有的开发人员,不能随便创建这个类的实例,从而有效避免该类被错误创建。

首先,instance必须是私有的并且静态的。如果不是私有的,那么instance的安全性无法得到保证。一个小小的意外就可能使得instance变成null。其次,因为工厂方法getInstance()必须是静态的,所以对应的instance也必须是静态的。

这个单例的性能是非常好的,由于getInstance()方法只是简单地返回instance,并没有任何锁操作,因此它在并行程序中会有良好的表现。

这种方式有一个明显不足,就是Singleton构造函数或者说Singleton实例在什么时候创建是不受控制的。对于静态成员instance,它会在类第一次初始化的时刻被创建。这个时刻并不一定是getInstance()方法第一次被调用的时刻。

比如,如果你的单例是这样的:
在这里插入图片描述
注意,这个单例还包含一个表示状态的静态成员STATUS。此时,在任何地方引用这个STATUS都会导致instance被创建(任何对Singleton方法或者字段的引用,都会导致类初始化,并创建instance,但是类初始化只有一次,因此instance永远只会被创建一次),比如:
在这里插入图片描述
上述方法会打印出:
在这里插入图片描述
可以看到,即使系统没有要求创建单例,new Singleton()方法也会被调用。

如果大家觉得这个小小的不足并不重要,那么这种单例模式也是一种不错的选择。它容易实现、代码易读而且性能优越。

如果你想精确控制instance的创建时间,那么这种方式就不太友善了。我们需要寻找一种新的方法、一种支持延迟加载的策略,它只会在instance第一次使用时创建对象,具体实现如下:
在这里插入图片描述
这个LazySingleton的核心思想是:最初我们并不需要实例化instance,而是当getInstance()方法被第一次调用时,创建单例对象。为了防止对象被多次创建,我们不得不使用synchronized关键字进行方法同步。这种实现的好处是,充分利用了延迟加载,只在真正需要时创建对象。但坏处也很明显,在并发环境下加锁,竞争激烈的场合对性能可能产生一定的影响。但总体上,这是一个非常易于理解和实现的方法。

上面介绍的两种单例实现可以说是各有千秋。有没有一种方法可以结合二者的优势呢?答案是肯定的。
在这里插入图片描述
上述代码实现了一个单例,并且同时拥有前两种方式的优点。首先getInstance()方法中没有锁,这使其在高并发环境下性能优越。其次,只有在getInstance()方法第一次被调用时,StaticSingleton的实例才会被创建。因为这种方法巧妙地使用了内部类和类的初始化方式。内部类SingletonHolder被声明为私有的,这使得我们不可能在外部访问并初始化它。而我们只可能在getInstance()方法内部对SingletonHolder类进行初始化,利用虚拟机的类初始化机制创建单例。

2、不变模式

在并行软件开发过程中,同步操作似乎是必不可少的。当多线程对同一个对象进行读写操作时,为了保证对象数据的一致性和正确性,有必要对对象进行同步,但是同步操作对系统性能有损耗。为了尽可能地去除这些同步操作、提高并行程序性能,可以使用一种不可改变的对象。依靠对象的不变性,可以确保其在没有同步操作的多线程环境中依然保持内部状态的一致性和正确性。这就是不变模式。

不变模式天生就是多线程友好的,它的核心思想是,一个对象一旦被创建,它的内部状态将永远不会发生改变。没有一个线程可以修改其内部状态和数据,同时其内部状态也绝不会自行发生改变。基于这些特性,对不变对象的多线程操作不需要进行同步控制。

同时需要注意,不变模式和只读属性是有一定的区别的。不变模式比只读属性具有更强的一致性和不变性。对只读属性的对象而言,对象本身不能被其他线程修改,但是对象的自身状态却可能自行修改。

比如,一个对象的存活时间(对象创建时间和当前时间的时间差)是只读的,任何一个第三方线程都不能修改这个属性,但是这是一个可变的属性,因为随着时间的推移,存活时间时刻都在发生变化。而不变模式则要求,无论出于什么原因,对象自创建后,其内部状态和数据都要保持绝对的稳定。

因此,不变模式的主要使用场景需要满足以下两个条件:

  • 当对象创建后,其内部状态和数据不再发生任何变化。
  • 对象需要被共享,被多线程频繁访问。

在Java语言中,不变模式的实现很简单。为确保对象被创建后,不发生任何改变,并保证不变模式正常工作,只需要注意以下四点即可:

  • 去除setter()方法及所有修改自身属性的方法。
  • 将所有属性设置为私有的,并用final标记,确保其不可修改。
  • 确保没有子类可以重载修改它的行为。
  • 有一个可以创建完整对象的构造函数。

以下代码实现了一个不变的产品对象,它拥有序列号、名称和价格三个属性:
在这里插入图片描述
在不变模式的实现中,final关键字起到了重要的作用。对属性的final定义确保所有数据只能在对象被构造时赋值1次。之后,就永远不发生改变。而对class的final定义确保了类不会有子类。根据里氏替换原则,子类可以完全替代父类。如果父类是不变的,那么子类也必须是不变的,但实际上我们无法约束这点,为了防止子类做出一些意外的行为,这里干脆把子类都禁用了。

在JDK中,不变模式的应用非常广泛。其中,最典型的就是java.lang.String类。此外,所有的元数据类、包装类都是使用不变模式实现的。主要的不变模式类型如下:
在这里插入图片描述
由于基本数据类型和String类型在实际的软件开发中应用极其广泛,使用不变模式后,所有实例的方法均不需要进行同步操作,保证了它们在多线程环境下的性能。

注意:不变模式通过回避问题而不是解决问题的态度来处理多线程并发访问控制,不变对象是不需要进行同步操作的。由于并发同步会对性能产生不良的影响,因此,在需求允许的情况下,不变模式可以提高系统的并发性能和并发量。

相关文章:

JAVA高并发——单例模式和不变模式

文章目录 1、探讨单例模式2、不变模式 由于并行程序设计比串行程序设计复杂得多,因此我强烈建议大家了解一些常见的设计方法。就好像练习武术,一招一式都是要经过学习的。如果自己胡乱打,效果不见得好。前人会总结一些武术套路,对…...

RabbitMQ(一):消息队列MQ

目录 1 消息队列MQ1.1 MQ简介1、什么是MQ2、MQ的优势流量削峰应用解耦异常处理数据分发分布式事务 3、消息中间件的弊端4、常用的MQ 1.2 MQ中几个基本概念1.3 MQ的通信模式1.4 消息的发布策略1.5 常用消息中间件协议1、AMQP协议2、MQTT协议3、OpenMessage协议4、kafaka协议 1 消…...

HarmonyOS—使用预览器查看应用/服务效果

DevEco Studio为开发者提供了UI界面预览功能,可以查看应用/服务的UI界面效果,方便开发者随时调整界面UI布局。预览器支持布局代码的实时预览,只需要将开发的源代码进行保存,就可以通过预览器实时查看应用/服务运行效果&#xff0c…...

大项目中,某个cpp文件读取所在包路径的方法

在一个比较大的C项目中,我们有很多包,每个包都有一个自己的src、include、CMakeLists.txt和其它文件,比如以下文件结构: project- pkg1- datas- data.json- src- xxx1.cpp- include- xxx1.h - CMakeLists.txt- pkg2- src- xxx2.…...

gem5学习(25):用于异构SoC的片上网络模型——Garnet2.0

目录 一、Invocation 二、Configuration 三、Topology 四、Routing 五、Flow Control 六、Router Microarchitecture 七、Buffer Management 八、Lifecycle of a Network Traversal 九、Running Garnet2.0 with Synthetic Traffic 官网教程:gem5: Garnet 2…...

康威生命游戏

康威生命游戏 康威生命游戏(Conway’s Game of Life)是康威发明的细胞自动机。 生命游戏有几个简单的规则&#xff1a; 细胞有两种状态&#xff0c;存活或死亡&#xff0c;每个细胞以自身为中心与周围的八格细胞互动。 对于存活的细胞&#xff1a; 当周围的细胞过少(<2)或…...

vscode与vue环境配置

一、下载并安装VScode 安装VScode 官网下载 二、配置node.js环境 安装node.js 官网下载 会自动配置环境变量和安装npm包(npm的作用就是对Node.js依赖的包进行管理)&#xff0c;此时可以执行 node -v 和 npm -v 分别查看node和npm的版本号&#xff1a; 配置系统变量 因为在执…...

Linux的ACL权限以及特殊位和隐藏属性

前言&#xff1a; ACL是什么&#xff1f; ACL&#xff08;Access Control List&#xff09;是一种权限控制机制&#xff0c;用于在Linux系统中对文件和目录进行细粒度的访问控制。传统的Linux权限控制机制基于所有者、所属组和其他用户的三个权限类别&#xff08;读、写、执行…...

使用openai-whisper实现语音转文字

使用openai-whisper实现语音转文字 1 安装依赖 1.1 Windows下安装ffmpeg FFmpeg是一套可以用来记录、转换数字音频、视频&#xff0c;并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的完整解决方案。 # ffmpeg官网 https://ffm…...

C++模板为什么不能声明和定义分离

首先我们要直到C程序运行需要进行的四个阶段。 预处理->编译->汇编->链接 编译&#xff1a;对语法语义分析&#xff0c;分析无误生成汇编&#xff0c;头文件不参加编译&#xff0c;多个源文件是分开单独编译的。 链接&#xff1a;将多个obj文件链接合成一个&#x…...

啊丢的刷题记录手册

1.洛谷题P1923 求第k小的数 题目描述 输入 n&#xff08;1≤n<5000000 且 n 为奇数&#xff09;个数字ai​&#xff08;1≤ai​<109&#xff09;&#xff0c;输出这些数字的第 k 小的数。最小的数是第 0 小。 请尽量不要使用 nth_element 来写本题&#xff0c;因为本题…...

用nginx正向代理https网站

目录 1. 缘起2. 部署nginx3. 测试3.1 http测试3.2 https测试4 给centos设置代理访问外网 1. 缘起 最近碰到了一个麻烦事情&#xff0c;就是公司的centos测试服务器放在内网环境&#xff0c;而且不能直接上外网&#xff0c;导致无法通过yum安装软件&#xff0c;非常捉急。   幸…...

面向对象设计模式

一、单例 一个类只能创建唯一一个对象 利用限制构造、static完成 二、工厂模式 优势&#xff1a;规范接口&#xff08;纯虚函数&#xff09;&#xff1b;实现多态&#xff08;虚函数表&#xff09;&#xff1b;继承 1、简单工厂 一个工厂创建所有产品。 返回基类指针可…...

人工智能_CPU微调ChatGLM大模型_使用P-Tuning v2进行大模型微调_007_微调_002---人工智能工作笔记0102

这里我们先试着训练一下,我们用官方提供的训练数据进行训练. 也没有说使用CPU可以进行微调,但是我们先执行一下试试: https://www.heywhale.com/mw/project/6436d82948f7da1fee2be59e 可以看到说INT4量化级别最低需要7GB显存可以启动微调,但是 并没有说CPU可以进行微调.我们…...

Android自编译Pixel3内核加入KernelSU

背景 让Pixel3 AOSP Android10 4.9内核用上Kernel SU 环境: Ubuntu 18.04 vm aosp10r2 移植参考官方,和github项目 Commits OnlyTomInSecond/android_kernel_xiaomi_sdm845 (github.com) 这个项目是 LineageOS/android_kernel_xiaomi_sdm845 编译的前提 已经有完整…...

Go 数据库编程精粹:database/sql 实用技巧解析

Go 数据库编程精粹&#xff1a;database/sql 实用技巧解析 简介database/sql 库的基础知识核心概念连接池驱动事务 环境配置 建立数据库连接连接到数据库示例&#xff1a;连接 MySQL 数据库连接池管理 执行查询和处理结果基本查询执行多行查询执行单行查询 结果处理处理多行结果…...

AI-Gateway:一款整合了OpenAI、Anthropic、LLama2等大语言模型的统一API接口

关于AI-Gateway AI-Gateway是一款针对大语言模型的统一API接口&#xff0c;该接口可以用在应用程序和托管的大语言模型&#xff08;LLM&#xff09;之间&#xff0c;该工具可以允许我们通过一个统一的API接口将API请求转发给OpenAI、Anthropic、Mistral、LLama2、Anyscale、Go…...

Android 广播的基本概念

一.广播简介 Broadcast是安卓四大组件之一。安卓为了方便进行系统级别的消息通知&#xff0c;引入了一套广播消息机制。打个比方&#xff0c;记得原来在上课的时候&#xff0c;每个班级的教室里都会装有一个喇叭&#xff0c;这些喇叭都是接入到学校的广播室的&#xff0c;一旦…...

【Docker实操】部署php项目

概述 最终达成的容器部署结构和原理如下图&#xff1a; 一、获取nginx、php官方镜像 docker pull nginx //拉取nginx官方镜像 docker pull php:7.4-fpm //拉取php官方镜像需要获取其他可用的php版本&#xff0c;可以上【docker hub】搜索【php】&#xff0c;所有的【xxx-fp…...

多线程-初阶

1. 认识线程&#xff08; Thread &#xff09; 1.1 概念 1) 线程是什么 一个线程就是一个 " 执行流 ". 每个线程之间都可以按照顺讯执行自己的代码 . 多个线程之间 " 同时 " 执行 着多份代码 . 还是回到我们之前的银行的例子中。之前我们主要描…...

Object和Function是函数,函数都有一个prototype属性

Object 和 Function 都是 JavaScript 自带的函数对象 在 JavaScript 中&#xff0c;万物皆对象&#xff0c;你要一个吗&#xff1f;new Object() 啊&#xff01; 当然&#xff0c;就好比同样为人&#xff0c;也区分普通人和天才。 对象也是有分类的&#xff0c;分为 普通对象…...

stm32利用CubeMX按键控制数码管加减数

首先画电路图&#xff1a; 接下来配置CubeMX&#xff1a; 设置好后生成MDK工程文件&#xff1a; 用keil打开工程&#xff1a; 添加部分代码&#xff1a; /* USER CODE BEGIN Includes */ uint16_t duan[]{0xC0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90}; uint1…...

前端页面生成条形码,借助layui打印标签

借助JsBarcode生成条形码 官网&#xff1a;https://lindell.me/JsBarcode/ github: https://github.com/lindell/JsBarcode <div class"table-div" style"display: block;width: 300px; height: 241px; margin: auto;"><table border"1&quo…...

第1~8章 综合复习

1. 重置root密码 1. 重启服务器&#xff08;虚拟机&#xff09;2. 快速选择第二项&#xff0c;然后按 e 键3. 在linux这一行的最后加上一个空格&#xff0c;然后输入 rd.break&#xff0c;然后按 ctrl x 来重启服务4. 在提示符所在位置输入 mount -o remount,rw /sysroot5. 在…...

转运机器人,AGV底盘小车:打造高效、精准的汽车电子生产线

为了满足日益增长的市场需求&#xff0c;保持行业领先地位&#xff0c;某汽车行业电子产品企业引入富唯智能AMR智能搬运机器人及其智能物流解决方案&#xff0c;采用自动化运输措施优化生产节拍和搬运效率&#xff0c;企业生产效率得到显著提升。 项目背景&#xff1a; 1、工厂…...

Spring Boot 的参数校验方案

1、前言 在平时的开发工作中,我们通常需要对接口进行参数格式验证。当参数个数较少(个数小于3)时,可以使用if ... else ...手动进行参数验证。当参数个数大于3个时,使用if ... else ...进行参数验证就会让代码显得臃肿,这个时候推荐使用注解来进行参数验证。 2、常用注…...

第N3周:Pytorch文本分类入门

>- **&#x1f368; 本文为[&#x1f517;365天深度学习训练营](https://mp.weixin.qq.com/s/rbOOmire8OocQ90QM78DRA) 中的学习记录博客** >- **&#x1f356; 原作者&#xff1a;[K同学啊 | 接辅导、项目定制](https://mtyjkh.blog.csdn.net/)** import torch import…...

宝塔面板安装了mysql5.7和phpMyadmin,但是访问phpMyadmin时提示502 Bad Gateway

操作流程截图如下&#xff1a; 原因是没有选择php版本 选择php版本 下一页找到phpMyAdmin&#xff0c;选择设置 目前只有纯净态&#xff0c;说明没有php环境&#xff0c;前去安装php环境 点击安装&#xff0c;选择版本&#xff0c;这里选择的是7.4版本&#xff0c;编译安…...

K8S—Pod详解

目录 一 Pod基础概念 1.1 Pod是什么 1.2 为什么要使用Pod&#xff1f;Pod在K8S集群中的使用方式&#xff1f; 1.3 基础容器pause 二 Pod的分类 2.1 自主式Pod和控制器管理的Pod 2.2 容器的分类 2.2.1 基础容器&#xff08;infrastructure container&#xff09; 2.2.2…...

深度学习中数据的转换

原始&#xff08;文本、音频、图像、视频、传感器等&#xff09;数据被转化成结构化且适合机器学习算法或深度学习模型使用的格式。 原始数据转化为结构化且适合机器学习和深度学习模型使用的格式&#xff0c;通常需要经历以下类型的预处理和转换&#xff1a; 文本数据&#xf…...

找人做网站价格/seo科技网

在一个运行超过半年的测试结果分析程序中&#xff0c;经理提出了一个新的要求&#xff0c;需要得到每一次单元测试运行的结果趋势图,以framework为类别显示是成功还是失败。当时的数据库中其中一个大表已经还有超过600万行记录&#xff0c;可以预计在接下来的时间中&#xff0c…...

外贸哪家做网站/百度ai人工智能平台

函数的格式 使用 function定义一个函数 function 函数名() { 函数体 } #!/bin/bashfunction sum() {s0;s$[$1 $2];echo "求和的结果为: "$s; }read -p "请输入需要求和的第一个数: num1" num1 read -p "请输入需要求和的第二个数: num2" num…...

网站开发所使用的浏览器/企业网站模板源码

密钥登录步骤&#xff08;免密码登录&#xff09; ssh登录提供两种认证方式&#xff1a;口令(密码)认证方式和密钥认证方式。其中口令(密码)认证方式是我们最常用的一种&#xff0c;出于安全方面的考虑&#xff0c;介绍密钥认证方式登录到linux/unix的方法。 使用密钥登录分为3…...

北京网站建设维护/网上交易平台

表单 json这是一个客户表单JSON文件的示例&#xff0c;您可能会看到该文件用于存储配置设置以设置系统。 它也可以用来包含记录信息&#xff0c;这些记录信息可以使用简单的JSON格式在各个组件之间轻松共享。 另外&#xff1a; 请参阅更多JSON示例。 {"firstName":…...

专业网站维护/服务营销的七个要素

点击上方“Java基基”&#xff0c;选择“设为星标”做积极的人&#xff0c;而不是积极废人&#xff01;源码精品专栏 原创 | Java 2020 超神之路&#xff0c;很肝~中文详细注释的开源项目RPC 框架 Dubbo 源码解析网络应用框架 Netty 源码解析消息中间件 RocketMQ 源码解析数据库…...

广州互联网公司排行榜/兰州网络推广优化怎样

Word2010会自动产生编号&#xff0c;相当方便。可是也有一些用户觉得这个功能“自作聪明”想取消它&#xff0c;那么可按如下方法操作。 方法1、产生自动编号后&#xff0c;再按一次<Enter>键。 方法2、产生自动编号后&#xff0c;按下<CtrlZ>组合键。 方法3、如果…...