做个外贸网站一般需要多少钱/如何设计企业网站

做个外贸网站一般需要多少钱,如何设计企业网站,河南室内设计公司排名,松原做网站的公司原子类和 volatile异同 首先,通过我们对原子类和的了解,原子类和volatile 都能保证多线程环境下的数据可见性。在多线程程序中,每个线程都有自己的工作内存,当多个线程访问共享变量时,可能会出现一个线程修改了共享变…

原子类和 volatile异同

首先,通过我们对原子类和的了解,原子类和volatile 都能保证多线程环境下的数据可见性。在多线程程序中,每个线程都有自己的工作内存,当多个线程访问共享变量时,可能会出现一个线程修改了共享变量的值,而其他线程不能及时看到最新值的情况。原子类和volatile关键字都能在一定程度上解决这个问题。例如,当一个变量被volatile修饰后,对该变量的写操作会立即刷新到主内存,读操作会直接从主内存读取,保证了其他线程能看到最新的值;原子类同样可以保证对变量操作的结果能被其他线程及时看到。

下面我们通过一个代码去看看它们的差异:

/*** 该类用于演示 volatile 关键字和 AtomicInteger 类在多线程环境下的不同表现。* 展示了使用 volatile 变量和 AtomicInteger 类进行自增操作的差异。*/
public class VolatileVsAtomic {// 用 volatile 修饰的变量,保证变量的可见性,但不保证操作的原子性private static volatile int volatileCount = 0;// 原子类,提供原子操作,保证操作的原子性private static AtomicInteger atomicCount = new AtomicInteger(0);/*** 主方法,程序的入口点。* 创建多个线程,分别对 volatile 变量和 AtomicInteger 类的实例进行自增操作,并输出结果。** @param args 命令行参数* @throws InterruptedException 如果线程在等待时被中断*/public static void main(String[] args) throws InterruptedException {// 定义线程数量int threadCount = 10;// 创建线程数组Thread[] threads = new Thread[threadCount];// 使用 volatile 变量进行自增操作for (int i = 0; i < threadCount; i++) {// 创建线程threads[i] = new Thread(() -> {// 每个线程执行 1000 次自增操作for (int j = 0; j < 1000; j++) {// 此操作不是原子性的,可能会出现数据竞争问题volatileCount++;}});// 启动线程threads[i].start();}// 等待所有线程执行完毕for (Thread thread : threads) {thread.join();}// 输出 volatile 变量的最终值System.out.println("Volatile count: " + volatileCount);// 重置计数器volatileCount = 0;atomicCount.set(0);// 使用原子类进行自增操作for (int i = 0; i < threadCount; i++) {// 创建线程threads[i] = new Thread(() -> {// 每个线程执行 1000 次自增操作for (int j = 0; j < 1000; j++) {// 原子性自增操作,保证操作的原子性atomicCount.incrementAndGet();}});// 启动线程threads[i].start();}// 等待所有线程执行完毕for (Thread thread : threads) {thread.join();}// 输出 AtomicInteger 类实例的最终值System.out.println("Atomic count: " + atomicCount.get());}
}

 输出结果如下:

在上述代码中,volatileCount是一个被volatile修饰的变量,多个线程对其进行自增操作时,由于自增操作不是原子性的,最终结果可能小于预期值;而atomicCount是一个AtomicInteger类型的原子类,多个线程对其进行自增操作时,能保证操作的原子性,最终结果是准确的。

原子类和 volatile 的使用场景

那下面我们就来说一下原子类和 volatile 各自的使用场景。

我们可以看出,volatile 和原子类的使用场景是不一样的,如果我们有一个可见性问题,那么可以使用 volatile 关键字,但如果我们的问题是一个组合操作,需要用同步来解决原子性问题的话,那么可以使用原子变量,而不能使用 volatile 关键字。

通常情况下,volatile 可以用来修饰 boolean 类型的标记位,因为对于标记位来讲,直接的赋值操作本身就是具备原子性的,再加上 volatile 保证了可见性,那么就是线程安全的了。

而对于会被多个线程同时操作的计数器 Counter 的场景,这种场景的一个典型特点就是,它不仅仅是一个简单的赋值操作,而是需要先读取当前的值,然后在此基础上进行一定的修改,再把它给赋值回去。这样一来,我们的 volatile 就不足以保证这种情况的线程安全了。我们需要使用原子类来保证线程安全。

原子类和 synchronized异同

原子类和 synchronized 关键字都可以用来保证线程安全,下面我们分别用原子类和 synchronized 关键字来解决一个经典的线程安全问题,给出具体的代码对比,然后再分析它们背后的区别。

首先,原始的线程不安全的情况的代码如下所示:

/*** BaseTest 类实现了 Runnable 接口,用于演示多线程并发修改共享变量的情况。* 该类包含一个静态变量 value,多个线程会同时对其进行递增操作。*/
public class BaseTest implements Runnable{// 静态变量 value,用于存储线程递增的结果static int value = 0;/*** main 方法是程序的入口点,创建并启动两个线程来执行 BaseTest 实例的 run 方法。* 等待两个线程执行完毕后,打印最终的 value 值。* * @param args 命令行参数* @throws InterruptedException 如果线程在等待过程中被中断*/public static void main(String[] args) throws InterruptedException {// 创建 BaseTest 实例Runnable runnable = new BaseTest();// 创建第一个线程并传入 BaseTest 实例Thread thread1 = new Thread(runnable);// 创建第二个线程并传入 BaseTest 实例Thread thread2 = new Thread(runnable);// 启动第一个线程thread1.start();// 启动第二个线程thread2.start();// 等待第一个线程执行完毕thread1.join();// 等待第二个线程执行完毕thread2.join();// 打印最终的 value 值System.out.println(value);}/*** run 方法是 Runnable 接口的实现,包含一个循环,将 value 变量递增 10000 次。*/@Overridepublic void run() {// 循环 10000 次,每次将 value 加 1for (int i = 0; i < 10000; i++) {value++;}}
}

在代码中我们新建了一个 value 变量,并且在两个线程中对它进行同时的自加操作,每个线程加 10000次,然后我们用 join 来确保它们都执行完毕,最后打印出最终的数值。

因为 value++ 不是一个原子操作,所以上面这段代码是线程不安全的,所以代码的运行结果会小于 20000,例如我执行的结果如下:

我们首先给出方法一,也就是用原子类来解决这个问题,代码如下所示:

/*** AtomicTest 类实现了 Runnable 接口,用于演示使用 AtomicInteger 进行线程安全的计数操作。* 该类创建了两个线程,每个线程都会对一个静态的 AtomicInteger 实例进行 10000 次递增操作。* 最后,主线程等待两个子线程执行完毕,并输出最终的计数值。*/
public class AtomicTest implements Runnable {// 静态的 AtomicInteger 实例,用于线程安全的计数操作static AtomicInteger atomicInteger = new AtomicInteger();/*** 程序的入口点,创建并启动两个线程,等待它们执行完毕,然后输出最终的计数值。** @param args 命令行参数,在本程序中未使用。* @throws InterruptedException 如果在等待线程执行完毕时被中断。*/public static void main(String[] args) throws InterruptedException {// 创建一个 AtomicTest 实例,作为线程的任务Runnable runnable = new AtomicTest();// 创建第一个线程并传入任务Thread thread1 = new Thread(runnable);// 创建第二个线程并传入任务Thread thread2 = new Thread(runnable);// 启动第一个线程thread1.start();// 启动第二个线程thread2.start();// 等待第一个线程执行完毕thread1.join();// 等待第二个线程执行完毕thread2.join();// 输出最终的计数值System.out.println(atomicInteger.get());}/*** 实现 Runnable 接口的 run 方法,该方法会对 atomicInteger 进行 10000 次递增操作。*/@Overridepublic void run() {// 循环 10000 次,每次对 atomicInteger 进行递增操作for (int i = 0; i < 10000; i++) {// 原子地递增 atomicInteger 的值并返回更新后的值atomicInteger.incrementAndGet();}}
}

用原子类之后,我们的计数变量就不再是一个普通的 int 变量了,而是 AtomicInteger 类型的对象,并且自加操作也变成了 incrementAndGet 法。由于原子类可以确保每一次的自加操作都是具备原子性的,所以这段程序是线程安全的,所以以上程序的运行结果会始终等于 20000。

下面我们给出方法二,我们用 synchronized 来解决这个问题,代码如下所示:

/*** SynTest 类用于演示多线程环境下的同步机制。* 该类实现了 Runnable 接口,多个线程可以共享同一个实例来执行任务。* 通过同步块确保对静态变量 value 的安全访问。*/
public class SynTest  implements Runnable {// 静态变量,用于记录所有线程累加的结果static int value = 0;/*** 程序的入口点,创建并启动两个线程来执行任务。** @param args 命令行参数* @throws InterruptedException 如果线程在等待时被中断*/public static void main(String[] args) throws InterruptedException {// 创建 SynTest 类的实例Runnable runnable = new SynTest();// 创建第一个线程并传入 Runnable 实例Thread thread1 = new Thread(runnable);// 创建第二个线程并传入 Runnable 实例Thread thread2 = new Thread(runnable);// 启动第一个线程thread1.start();// 启动第二个线程thread2.start();// 等待第一个线程执行完毕thread1.join();// 等待第二个线程执行完毕thread2.join();// 输出最终累加结果System.out.println(value);}/*** 实现 Runnable 接口的 run 方法,定义线程要执行的任务。* 在这个方法中,线程会对静态变量 value 进行 10000 次累加操作。*/@Overridepublic void run() {// 循环 10000 次for (int i = 0; i < 10000; i++) {// 使用同步块确保同一时间只有一个线程可以访问和修改 value 变量synchronized (this) {// 对 value 变量进行累加操作value++;}}}
}

它与最开始的线程不安全的代码的区别在于,在 run 方法中加了 synchronized 代码块,就可以非常轻松地解决这个问题,由于 synchronized 可以保证代码块内部的原子性,所以以上程序的运行结果也始终等于 20000,是线程安全的。

原子类和 synchronized 的使用对比

下面我们就对这两种不同的方案进行分析。

第一点,我们来看一下它们背后原理的不同。

synchronized 保证线程安全的核心是 monitor 锁,同步方法和同步代码块的背后原理会有少许差异,但总体思想是一致的:在执行同步代码之前,需要首先获取到 monitor 锁,执行完毕后,再释放锁。而原子类保证线程安全的原理是利用了 CAS 操作。从这一点上看,虽然原子类和 synchronized 都能保证线程安全,但是其实现原理是大有不同的。

第二点不同是使用范围的不同。

对于原子类而言,它的使用范围是比较局限的。因为一个原子类仅仅是一个对象,不够灵活。而synchronized 的使用范围要广泛得多。比如说 synchronized 既可以修饰一个方法,又可以修饰一段代码,相当于可以根据我们的需要,非常灵活地去控制它的应用范围。

所以仅有少量的场景,例如计数器等场景,我们可以使用原子类。而在其他更多的场景下,如果原子类不适用,那么我们就可以考虑用 synchronized 来解决这个问题。

第三个区别是粒度的区别。

原子变量的粒度是比较小的,它可以把竞争范围缩小到变量级别。通常情况下,synchronized 锁的粒度都要大于原子变量的粒度。如果我们只把一行代码用 synchronized 给保护起来的话,有一点杀鸡焉用牛刀的感觉。

第四点是它们性能的区别,同时也是悲观锁和乐观锁的区别。

因为 synchronized 是一种典型的悲观锁,而原子类恰恰相反,它利用的是乐观锁。所以,我们在比较synchronized 和 AtomicInteger 的时候,其实也就相当于比较了悲观锁和乐观锁的区别。

从性能上来考虑的话,悲观锁的操作相对来讲是比较重量级的。因为 synchronized 在竞争激烈的情况下,会让拿不到锁的线程阻塞,而原子类是永远不会让线程阻塞的。不过,虽然 synchronized 会让线程阻塞,但是这并不代表它的性能就比原子类差。

因为悲观锁的开销是固定的,也是一劳永逸的。随着时间的增加,这种开销并不会线性增长。而乐观锁虽然在短期内的开销不大,但是随着时间的增加,它的开销也是逐步上涨的。

所以从性能的角度考虑,它们没有一个孰优孰劣的关系,而是要区分具体的使用场景。在竞争非常激烈的情况下,推荐使用 synchronized;而在竞争不激烈的情况下,使用原子类会得到更好的效果。

值得注意的是,synchronized 的性能随着 JDK 的升级,也得到了不断的优化。synchronized 会从无锁升级到偏向锁,再升级到轻量级锁,最后才会升级到让线程阻塞的重量级锁。因此synchronized 在竞争不激烈的情况下,性能也是不错的。

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

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

相关文章

207、【图论】孤岛的总面积

题目 思路 相比于 206、【图论】岛屿数量&#xff0c;就是在这个代码的基础上。先遍历边界&#xff0c;将边界连接的岛屿变为0&#xff0c;然后再计算一遍当前为1的岛屿面积。 代码实现 import collectionsn, m list(map(int, input().split())) graph []for _ in range(n…

【GPT入门】第21课 langchain核心组件

【GPT入门】第21课 langchain核心组件 1. langchain 核心组件2.文档加载器 Document loader3.文档处理器3.1 langchain_text_splitters3.3 FAISS向量数据库和向量检索主要作用应用场景4. 对话历史管理1. langchain 核心组件 模型 I/O 封装 LLMs:大语言模型 Chat Models:一般…

应急响应靶机练习-Linux2

1.背景 前景需要&#xff1a;看监控的时候发现webshell告警&#xff0c;领导让你上机检查你可以救救安服仔吗&#xff01;&#xff01; 挑战内容&#xff1a; &#xff08;1&#xff09;提交攻击者IP &#xff08;2&#xff09;提交攻击者修改的管理员密码(明文) &#xff08;…

分享一个免费的CKA认证学习资料

关于CKA考试 CKA&#xff08;Certified Kubernetes Administrator&#xff09;是CNCF基金会&#xff08;Cloud Native Computing Foundation&#xff09;官方推出的Kubernetes管理员认证计划&#xff0c;用于证明持有人有履行Kubernetes管理的知识&#xff0c;技能等相关的能力…

【最新】 ubuntu24安装 1panel 保姆级教程

系统&#xff1a;ubuntu24.04.1 安装软件 &#xff1a;1panel 第一步&#xff1a;更新系统 sudo apt update sudo apt upgrade 如下图 第二步&#xff1a;安装1panel&#xff0c;运行如下命令 curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o …

UE4-UE5虚幻引擎,前置学习一--Console日志输出经常崩溃,有什么好的解决办法

有些差异 这么牛逼的引擎&#xff0c;居然有这种入门级别的问题&#xff0c;一触发清理&#xff0c;大概率(80%)会崩溃 无论虚幻5还是UE4都有这个问题&#xff0c;挺烦人的 实在忍不了了&#xff0c;这次&#xff0c;今天 就想问问有什么好的处理方法么&#xff1f;&#x…

【微服务】Nacos 配置动态刷新(简易版)(附配置)

文章目录 1、实现方法2、配置依赖 yaml3、验证效果 1、实现方法 环境&#xff1a;Nacos、Java、SpringBoot等 主要是在boostrap.yaml中的data-id属性下配置refresh:true来实现动态更新 2、配置依赖 yaml 具体的版本参考官方的说明&#xff1a;官方版本说明 <!--读取boo…

设计模式之备忘录设计模式

备忘录设计模式&#xff08;Memento Pattern&#xff09; 在不破坏封闭的前提下&#xff0c;捕获一个对象的内部状态&#xff0c;保存对象的某个状态&#xff0c;以便在适当的时候恢复对象&#xff0c;又叫做快照模式&#xff0c;属于行为模式备忘录模式实现的方式需要保证被保…

【最后203篇系列】016 Q201架构思考

前言 Q200已经达到了我既定的目标&#xff0c;在最近的3个月&#xff0c;我需要进一步完善&#xff0c;达到可以试产的程度。 在这个过程当中&#xff0c;许多知识和体会一直在变。 qtv200到目前&#xff0c;虽然通过习惯(每晚运行离线策略和比对)方式维持了注意力的集中&…

音视频入门基础:RTP专题(20)——通过FFprobe显示RTP流每个packet的信息

通过FFprobe命令&#xff1a; ffprobe -protocol_whitelist "file,rtp,udp" -of json -show_packets XXX.sdp 可以显示SDP描述的RTP流每个packet&#xff08;数据包&#xff09;的信息&#xff1a; 对于RTP流&#xff0c;上述的“packet”&#xff08;数据包&#…

LLM后训练:解锁大型语言模型推理能力的关键路径

引言&#xff1a;从语言生成到逻辑推理的跃迁 大型语言模型&#xff08;LLMs&#xff09;通过预训练掌握了海量语言模式&#xff0c;但其核心缺陷——幻觉、逻辑断裂、价值观偏差——暴露了单纯预训练的局限性。后训练&#xff08;Post-Training&#xff09;作为预训练后的精修…

9.贪心算法

简单贪心 1.P10452 货仓选址 - 洛谷 #include<iostream> #include<algorithm> using namespace std;typedef long long LL; const int N 1e510; LL a[N]; LL n;int main() {cin>>n;for(int i 1;i < n;i)cin>>a[i];sort(a1,a1n);//排序 LL sum 0…

Linux 网络:skb 数据管理

文章目录 1. 前言2. skb 数据管理2.1 初始化2.2 数据的插入2.2.1 在头部插入数据2.2.2 在尾部插入数据 2.2 数据的移除 3. 小结 1. 前言 限于作者能力水平&#xff0c;本文可能存在谬误&#xff0c;因此而给读者带来的损失&#xff0c;作者不做任何承诺。 2. skb 数据管理 数…

批量给 Excel 添加或删除密码保护|Excel 批量设置打开密码和只读密码

我们在将 Excel 文档发送给第三方或者进行存档的时候&#xff0c;对 Excel 文档添加密码保护是非常重要的一个操作。添加保护后的 Excel 文档。就只能有相应权限的用户才能够打开或者编辑操作。尤其是当我们 Excel 文档中内容非常敏感非常重要的时候&#xff0c;添加保护就显得…

蓝耘MaaS平台:阿里QWQ应用拓展与调参实践

摘要&#xff1a;本文深入探讨了蓝耘MaaS平台与阿里QWQ模型的结合&#xff0c;从平台架构、模型特点到应用拓展和调参实践进行了全面分析。蓝耘平台凭借其强大的算力支持、弹性资源调度和全栈服务&#xff0c;为QWQ模型的高效部署提供了理想环境。通过细化语义描述、调整推理参…

使用 Docker 部署前端项目全攻略

文章目录 1. Docker 基础概念1.1 核心组件1.2 Docker 工作流程 2. 环境准备2.1 安装 Docker2.2 验证安装 3. 项目配置3.1 项目结构3.2 创建 Dockerfile 4. 构建与运行4.1 构建镜像4.2 运行容器4.3 访问应用 5. 使用 Docker Compose5.1 创建 docker-compose.yml5.2 启动服务5.3 …

springboot集成flink实现DM数据库同步到ES

前言 今天分享的其实是一个面试上机方案&#xff0c;就是监测DM数据库数据&#xff0c;同步到ES&#xff0c;使用flink实现。基本套路&#xff0c;其实也没啥好说的&#xff0c;非要说也就是&#xff0c;国家队还是很多不跟你玩啊&#xff0c;虽然flink有阿里在背后&#xff0c…

【蓝桥杯】24省赛:数字串个数

思路 本质是组合数学问题&#xff1a; 9个数字组成10000位数字有9**10000可能 不包括3的可能8**10000 不包括7的可能8**10000 既不包括3也不包括77**10000 根据容斥原理&#xff1a;结果为 9 ∗ ∗ 10000 − 8 ∗ ∗ 10000 − 8 ∗ ∗ 10000 7 ∗ ∗ 10000 9**10000 - 8**10…

Unity开发中对象池设计与使用

一、设计目的 为了避免频繁创建和销毁对象&#xff08;例如 UI 元素、事件对象等&#xff09;带来的内存分配和垃圾回收压力&#xff0c;可以使用对象池来管理对象来提高游戏的性能&#xff0c;避免游戏卡顿。 二、代码实现 public interface IRecycle {/// <summary>…

JVM并发编程AQSsync锁ReentrantLock线程池ThreadLocal

并发编程2 synchronized锁实现**AQS****ReentrantLock实现****JUC 常用类**池的概念 ThreadLocalThreadLocal原理内存泄露强引用:软引用弱引用虚引用ThreadLocal内存泄露 synchronized锁实现 synchronized是一个关键字,实现同步,还需要我们提供一个同步锁对象,记录锁状态,记录…