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

机械设备采购平台东莞seo托管

机械设备采购平台,东莞seo托管,开发公司销售人员竞聘演讲稿,嘉兴做网站优化多少钱目录 一,统计案例 1.1 原生代码 1.2 追加volatile关键字 1.3 追加 synchronized 关键字 二,总结 2.1 关键字总结 2.2 原子性,可见性,有序性 2.3【总结】 三,系列文章推荐 一,统计案例 在上一章…

目录

一,统计案例

1.1 原生代码

1.2 追加volatile关键字

1.3 追加 synchronized 关键字

二,总结

2.1 关键字总结

2.2 原子性,可见性,有序性

2.3【总结】

三,系列文章推荐


一,统计案例   

         在上一章《多线程基础讲解》中提到多线程的基础使用,生命周期,常用API等基本使用的知识点。并且我们可以体会到每个子任务可以交给不同的线程执行,实现真正的“分而治之”。

        在多线程进行任务分批处理的时候。如何做到资源在实时更新的同时也能被其他线程及时感知到。多线程在资源共享与资源竞争提供哪些机制确保数据的一致性。通过一个案例讲解。

1.1 原生代码

/*** @author toast* @time 2025/3/19* @remark*/
class Counter {private int count = 0;public void increment() {count++; // 不是原子操作}public int getCount() {return count;}
}public class RaceConditionExample {public static void main(String[] args) throws InterruptedException {Counter counter = new Counter();// 创建两个线程同时修改 count 变量追加10000次Thread t1 = new Thread(() -> {IntStream.range(0, 10000).forEach(i -> counter.increment());System.out.println("T1执行完毕");});Thread t2 = new Thread(() -> {IntStream.range(0, 10000).forEach(i -> counter.increment());System.out.println("T2执行完毕");});t1.start();t2.start();t1.join(); // main主线程等待t1线程执行完毕t2.join(); // main主线程等待t2线程执行完毕System.out.println("最终 count 值:" + counter.getCount());}
}

输出结果:

T2执行完毕
T1执行完毕
最终 count 值:17829

        输出结果并非20000。而是一个 17829。这是为什么?我们可以先讲一下这个赋值过程我们就知道了。

        从统计算计的赋值流程,我们可以了解到线程T1,T2分别先从主内存(Main memory)读取 count = 10; 之后又各自运行各自的统计业务。在这过程之中线程之间的工作内存又是不共享,相当于两个线程同时读取 10 并执行 +1,最终 count 只增加了一次,变成 11❌。

1.2 追加volatile关键字

        在1.1 的案例当中,我们发现线程每一次都需要进行从主内存进行一次数据读取到线程的工作内存之中,现在通过 volatile 关键字,让其线程直接使用主内存(Main momery)的数据。代码如下

package com.toast.javase.source.thread;import java.util.stream.IntStream;/*** @author toast* @time 2025/3/19* @remark*/
class VolatileCounter {private volatile int count = 0;public void increment() {count++; // 仍然不是原子操作}public int getCount() {return count;}
}public class VolatileExample {public static void main(String[] args) throws InterruptedException {VolatileCounter counter = new VolatileCounter();Thread t1 = new Thread(() -> {IntStream.range(0, 10000).forEach(i -> counter.increment());System.out.println("T1执行完毕");});Thread t2 = new Thread(() -> {IntStream.range(0, 10000).forEach(i -> counter.increment());System.out.println("T2执行完毕");});t1.start();t2.start();t1.join();t2.join();System.out.println("最终 count 值:" + counter.getCount());}
}

输出结果

T1执行完毕
T2执行完毕
最终 count 值:18499

        现在追加了 volatile 关键字,使其线程之间的count是可见的,就算数据修改了,其他线程也是可以感知到了。但是为什么还不是 20000?观察如下示意图

        count 追加了 volatile 关键字,确实实现了线程之间的数据可见性,但没有解决count数据覆盖导致统计失败。其原因就是T1, T2 在争抢资源的时候没有一个界限。按道理第二次计算,不管是T1执行第二次计算,还是T2执行第二次计算,其读取到的值应该是count = 11; 而非 count = 10;

        而这个界限,或者说临界点的开放与关闭在 JVM里面提供一个关键字,这个关键字就是synchronized,也被称为“内置锁”( Intrinsic Lock )。

1.3 追加 synchronized 关键字

package com.toast.javase.source.thread;import java.util.stream.IntStream;/*** @author liuwq* @time 2025/3/19* @remark*/
class SynchronizedCounter {private volatile int count = 0;// 现在是线程安全的public synchronized void increment() {count++;}public int getCount() {return count;}
}public class SynchronizedExample {public static void main(String[] args) throws InterruptedException {SynchronizedCounter counter = new SynchronizedCounter();Thread t1 = new Thread(() -> {IntStream.range(0, 10000).forEach(i -> counter.increment());System.out.println("T1执行完毕");});Thread t2 = new Thread(() -> {IntStream.range(0, 10000).forEach(i -> counter.increment());System.out.println("T2执行完毕");});t1.start();t2.start();t1.join();t2.join();System.out.println("最终 count 值:" + counter.getCount()); // 结果一定是 20000}
}

输出结果

T1执行完毕
T2执行完毕
最终 count 值:20000

        赋值流程图如下

二,总结

2.1 关键字总结

        从上面的统计案例当中,我们知道了关键字 volatile 以及 synchronized 关键字的作用。

volatile

作用一:保证了数据在线程之间的可见性,

作用二:防止CPU指令重排,上面案例并未明显体现

synchronized

作用一:保证了代码的互斥性,同一时间只允许一个线程执行。

作用二:保证了可见性,进入synchronized 代码之前,会从主内存读取数据,代码结束,退出synchronized代码,必须回写数据到主 内存。(问大家一个问题,如果数据没有 volatile 关键字修饰,还会从主内存读取数据吗?当然会了,只不过是读取完之后存储在自己的工作内存空间里,计算完再回写过去。只不过整个过程数据没有可见性)

作用三:保证了原子性,其代码内的操作是不可分割的

2.2 原子性,可见性,有序性

        其实在上面的 2.1 关键字总结上就已经总结出来了原子性,可见性(数据可见性),以及有序性

原子性

原子性,顾名思义,借用“原子”不可分割的性质。表示 一个操作要么全部执行成功,要么全部失败,不能被其他线程打断

可见性

可见性表示数据在线程之间是否可见,在修改变量数据时其他线程是否能感知到

有序性

有序性指的是程序执行的顺序符合代码编写的逻辑顺序,但由于 JVM JIT 编译器优化、CPU 指令重排(Instruction Reordering),实际执行顺序可能不同。

2.3【总结】

        对于保证原子性,JVM提供内置锁 synchronized 关键字,以及JDK1.5之后的Lock 接口。

        对于可见性,提供volatile 关键字,确保数据在线程之间的可见性

        对于有序性,也是 volatile 通过禁止 指令重排 来确保有序性。指令重排是 CPU 为提高性能而对程序指令执行顺序进行调整的技术。指令重排可能会导致线程看到不一致的状态,从而产生竞态条件。

  

        

三,系列文章推荐

        最后,如果这篇文章对你有帮助,欢迎 点赞👍、收藏📌、关注👀
        我会持续分享 Java、Spring Boot、MyBatis-Plus、微服务架构 相关的实战经验,记得关注,第一时间获取最新文章!🚀

        这篇文章是 【Java SE 17源码】系列 的一部分,详细地址:

java SE 17 源码篇_吐司呐的博客-CSDN博客

        记得 关注我,后续还会更新更多高质量技术文章!

你在实际开发中遇到过类似的问题吗?
欢迎在评论区留言交流,一起探讨 Java 开发的最佳实践! 🚀

http://www.dtcms.com/wzjs/423336.html

相关文章:

  • 做市场的逛的网站百度收录网站提交入口
  • 一般ps做网站大小多少抖音seo怎么收费
  • 北京沙河教做网站的浙江网站seo
  • 品牌网站怎么做seo苏州新闻今天最新消息新闻事件
  • 网站建设需要准备什么全媒体广告代理加盟
  • qt网站开发烘焙甜点培训学校
  • 做网站界面尺寸是多少网站建设优化的技巧
  • 海口网站开发建设百度关键词搜索指数
  • 做医疗的网站建设百度一下你就知道官网下载安装
  • 软件技术文档编写标准规范seo最新
  • 莱芜区组织部网站长沙百度推广排名
  • 毕设做网站怎么样种子搜索引擎 磁力天堂
  • 网站建设滚动条怎么插入大连seo网站推广
  • 东莞自适应网站建设优化大师客服
  • 沈阳做网站的网络营销策略理论有哪些
  • 学校网站的功能青岛谷歌seo
  • 白云网站建设怎么做网站教程
  • 东京热 在线A视频网站一级做爰片百度指数特点
  • 网站建设的界面f分优秀的网页设计网站
  • 独立ip网站建设外贸平台有哪些比较好
  • 如何创建一个网站的步骤环球网
  • 网站登录界面图片用什么软件做网络营销推广方案案例
  • 网站开发及后期维护汽车宣传软文
  • 个人博客网站模板wordpress整合营销什么意思
  • 独立做网站需要学习什么淘宝指数转换
  • 网站用户管理系统网站建设的意义和作用
  • 和初中生做视频网站厦门关键词seo排名网站
  • 戴尔网站建设成功巩义网站推广优化
  • 茶叶网站建设优化seo是什么
  • 网页源代码提取文件南昌搜索引擎优化