并发编程三大特性之可见性

一、什么是可见性?

               可见性问题是基于CPU位置出现的,cpu处里速度非常快,相对CPU来说去主内存

      获取数据这个事情太慢了,CPU就提供了 L1,L2,L3的三季缓存,每次去主内存拿完

      数据后,数据就先存储到三级缓存,然后cpu再去三级缓存取数据,效率肯定会提升;

      三级缓存就是是每个线程的工作内存,是相互独立的。

              这就带来了一个问题:现在CPU都是多核,每个线程的工作内存(CPU三级缓存)都

      是独立的,会告知每个线程做修改时,只修改自己的工作内存,数据没有及时同步到主内存

      ,从而导致数据不一致的问题

     线程运行时数据处里过程如下:

             

     使用下边代码来验证数据可见性的问题,代码如下:

             

             

二、解决可见性问题的方式

       1、volatile 

             volatile是一个关键字,用于修饰成员变量

              如果属性被volatile修饰,相当于告诉cpu,对于当前属性的操作,不允许使用CPU

              缓存(即线程私有内存),必须去操作主内存。

              volatile的内存语义:

                    (1)volatile 属性被写:当写一个volatile变量,JMM会将当前线程的CPU缓存的

                                 数据及时刷新到主内存中

                    (2)volatile 属性被读:当读一个volatile变量,JMM会将当前线程对应的CPU缓存

                                 设置为无效,必须从主内存读取数据。

               其实变量加了volatile就是告诉cpu,对当前变量的读写操作,不允许使用CPU缓存;加

               了volatile 的变量会在编译成汇编之后追加一个lock前缀,CPU执行这个指令时,如果

                带有lock前缀会做2件事:

                       (1)将当处理器缓存行的数据写回到主内存

                       (2)这个写会的数据,在其他的CPU内核的缓存中,直接无效

                  总结:volatile 就是让CPU每次操作这个数据时,必须立即同步到主内存,以及从主内

                             存读取数据。

                             在代码中若先对volatile属性进行操作,则其他属性也是可见性的。

               针对上边的代码,采用volatile解决可见性问题实现如下:

/******************************************************** 验证线程的可见性问题* 每个线程都有自己的私有内存,相互独立,线程运行时处里的是自己私有内存的数据** 使用volatile解决内存可见性*******************************************************/
public class Test02 {private volatile static boolean flag = true;public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {while (flag){}System.out.println("子线程 t1 中 flag改变");});t1.start();//预期:flag修改成false后,不影响线程t1的运行Thread.sleep(100);//修改flag 的值flag = false;System.out.println(" main 线程中修改 flag = false");}
}//方案二:在代码中若先对volatile属性进行操作,则其他属性也是可见性的
public class Test02 {private volatile static int i= 0;private  static boolean flag = true;public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {while (flag){//todo: 在代码中若先对volatile属性进行操作,则其他属性也是可见性的i++;}System.out.println("子线程 t1 中 flag改变");});t1.start();//预期:flag修改成false后,不影响线程t1的运行Thread.sleep(100);//修改flag 的值flag = false;System.out.println(" main 线程中修改 flag = false");}
}

       2、synchronized

              synchronized也是可以解决可见性问题。

              synchronized内存语义:

                      如果涉及到了synchronized 的同步代码块或者同步方法,获取资源之后,将内部

                      涉及到的变量从CPU缓存(线程私有内存)中移除,必须重新去主内存中取数据;

                      而且在释放锁之后,会立即将CPU缓存中的数据同步到主内存中。

              使用 synchronized 解决内存可见性 示例代码如下:

                           

/******************************************************** 验证线程的可见性问题* 每个线程都有自己的私有内存,相互独立,线程运行时处里的是自己私有内存的数据** 使用synchronized解决内存可见性*******************************************************/
public class Test03 {private  static boolean flag = true;public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {while (flag){/** 问题:为什么这里synchronized 放在while循环里边,不放在外边?*     因为线程 在获取到 synchronized 锁之后才会从主内存拿数据,若把synchronized 放在while外边*     则只会从主内存拿一次数据,后边不能监听到变量 flag 变化*/synchronized (Test03.class){//todo}}System.out.println("子线程 t1 中 flag改变");});t1.start();//预期:flag修改成false后,不影响线程t1的运行Thread.sleep(100);//修改flag 的值flag = false;System.out.println(" main 线程中修改 flag = false");}
}

       3、Lock

             Lock锁保证可见性的方式和synchronized 完全不同,synchronized是基于内存语义在获取

             锁和释放锁对CPU缓存做一个同步到主内存的操作。

             lock 锁是基于volatile实现的,lock 锁内部进行加锁和释放锁时,会对一个volatile修饰的属

             state做加减操作。

             如果对volatile属性进行写操作,CPU会执行带有lock前缀的指令,会将CPU缓存的数据立

             即同步到主内存,同时也会将其他非volatile属性页一起同步到主内存。还会将其他CPU缓

             存行 中这个volatile数据设置为无效,必须从主内存重新拉取。

             lock解决可见性示例代码如下:

                  

/******************************************************** 验证线程的可见性问题* 每个线程都有自己的私有内存,相互独立,线程运行时处里的是自己私有内存的数据** 使用lock解决内存可见性*******************************************************/
public class Test04 {private  static boolean flag = true;private static ReentrantLock lock = new ReentrantLock();public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {while (flag){lock.lock();try {//。。。。。}finally {lock.unlock();}}System.out.println("子线程 t1 中 flag改变");});t1.start();//预期:flag修改成false后,不影响线程t1的运行Thread.sleep(100);//修改flag 的值flag = false;System.out.println(" main 线程中修改 flag = false");}
}

       4、final

             final本质上说并不能像synchronized和volatile 那种形式保证可见性,final修饰的属性在

             运行期间是不允许修改的,这样一来就间接保证了可见性。

             final与volatile不允许同时修饰一个属性,final修饰的属性不允许被修改,而volatile保证

             每次从主内存读取数据,并且volatile会影响一定性能,就不需要同时修饰。

              final与volatile同时修饰属性会报错,如下图所示:

                   

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

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

相关文章

使用LIKE进行模糊查询

查询包含字符‘e’的信息 % 代表不确定个数的字符(零个或多个) SELECT employee_id, first_name FROM employees WHERE first_name LIKE %e%; 查询以字符‘e’开头的字符 SELECT employee_id, first_name FROM employees WHERE first_name LIKE e%; _…

腾讯云2024年优惠券领取及使用常见问题

腾讯云作为国内领先的云计算服务提供商,经常会推出各种优惠活动,以此来吸引用户上云。其中,优惠券作为一种常见的促销方式,受到了众多用户的青睐。然而,在领取和使用优惠券的过程中,大家可能会遇到一些常见…

1.《C语言》—— [常见概念]

前言: C语言是学习编程的一门语言,C语言概念少,词汇少,包含了基本的编程元素,再后来的很多语言如(C,Java)等都参考了C语言,所以想要学好编程,C语言是必不可少的一门&…

77、WAF攻防——权限控制代码免杀异或运算变量覆盖混淆加密传参

文章目录 WAF规则webshell免杀变异 WAF规则 函数匹配 工具指纹 webshell免杀变异 php 传参带入 eval可以用assert来替换,assert也可以将字符串当作php代码执行漏洞 php 变量覆盖 php 加密 使用加密算法对php后门进行加密 php 异或运算 简化:无字符webshellP 无数字字母rc…

《米小圈上学记》——让孩子爱上阅读一点也不难!

阅读能力的培养是小学语文素质教育重要的组成部分,阅读能力的高低,直接关系到学生的理解能力、运用知识的能力以及表达能力的提升。提高小学生的阅读能力不仅关系到小学生语文素养的培养,而且对他们开阔视野、提高内涵、增加底蕴、放飞心灵有…

哈希存节点,双dp数组存选和不选

小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为 root 。 除了 root 之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果 两个直接相连…

Linux:安装zabbix-agent被监控端(2)

本章是结合着上一篇文章的续作 Linux:部署搭建zabbix6(1)-CSDN博客https://blog.csdn.net/w14768855/article/details/137426966?spm1001.2014.3001.5501本章将在两台centos部署agent端,然后使用server进行连接监控 agent1 在1…

11、子串-滑动窗口最大值

题解: 双端队列是一种特殊的队列,允许你在队列的两端进行插入和删除操作。在滑动窗口问题中,我们使用它来存储可能是当前窗口最大值的元素的索引。 维护队列的顺序: 当新元素进入窗口时,我们将它与队列尾部的元素进…

《科技创业月刊》是什么级别的期刊?是正规期刊吗?能评职称吗?

问题解答:问:《科技创业月刊》是什么级别的刊物? 答:省级,主管单位: 湖北省科学技术厅 ;主办单位:湖北省科技信息研究院 问:《科技创业月刊》是c刊吗? 答&…

spring面试八股

常用的注册bean的方式 ComponentScan扫描到的service和Controller等的注解 Configration配置类或者是xml文件的定义。 spring中有几种依赖注入的方式 1.构造器注入。 2.setter方法注入。 3.使用field属性的方式注入。 applicationContext是什么 spring bean spring aop Aop…

2-django、http、web框架、django及django请求生命周期、路由控制、视图层

1 http 2 web框架 3 django 3.1 django请求生命周期 4 路由控制 5 视图层 1 http #1 http 是什么 #2 http特点 #3 请求协议详情-请求首行---》请求方式,请求地址,请求协议版本-请求头---》key:value形式-referer:上一次访问的地址-user-agen…

Sora是什么?Sora怎么使用?Sora最新案例视频以及常见问题答疑

Sora 是什么? 2024年2月16日,OpenAI 在其官网上面正式宣布推出文本生成视频的大模型Sora 这样说吧给你一段话, 让你写一篇800字的论文,你的理解很可能都有偏差,那么作为OpenAi要做文生视频到底有多难,下面…

科研学习|研究方法——扎根理论三阶段编码如何做?

一、背景介绍 “主题标引”意指对文献内容进行分析, 然后对文献所表达的中心思想、所讨论的基本问题以及研究的对象等进行提取, 以形成主题概念, 然后在此基础上把可检索的主题词表示出来, 再将这些主题词按一定顺序 (如字顺) 排列, 对论述相同主题内容的文献加以集中, 从而提高…

Linux下场景模拟--cpu、内存打满测试

Linux下场景模拟–cpu、内存打满测试 打满CPU占用 编写脚本vi /root/cpu_run_full.sh vi /root/cpu_run_full.sh填写如下内容&#xff1a; #!/bin/bash function while_run_cpu() {while true;doi2;done }function cpu_full() {for ((i0; i<$1; i));dowhile_run_cpu &am…

css伪类:last-child或:first-child不生效

目录 一、问题 二、原因及解决方法 三、总结 tiips:如嫌繁琐&#xff0c;直接移步总结即可&#xff01; 一、问题 1.想使用伪类:last-child给 for循环出来的最后一个元素单独添加样式。但是发现无论怎么写都没有添加上去。 2.真是奇怪呀&#xff0c;明明写的没有问题呀&a…

云备份day04

&#x1f4df;作者主页&#xff1a;慢热的陕西人 &#x1f334;专栏链接&#xff1a;C云备份项目 &#x1f4e3;欢迎各位大佬&#x1f44d;点赞&#x1f525;关注&#x1f693;收藏&#xff0c;&#x1f349;留言 主要内容介绍了文件工具了类的实现 文章目录 云备份day041.文件…

Matlab应用层生成简述

基础软件层 目前接触到的几款控制器&#xff0c;其厂商并没有提供simulink的基础软件库一般为底层文件被封装为lib&#xff0c;留有供调用API接口虽然能根据API接口开发基础软件库&#xff0c;但耗费时间过长得不偿失 应用层 所以可以将应用层封装为一个子系统&#xff0c;其…

Vue3组件基础示例

组件是vue中最推崇的&#xff0c;也是最强大的功能之一&#xff0c;就是为了提高重用性&#xff0c;减少重复性的开发。 如何使用原生HTML方法实现组件化 在使用原生HTML开发时&#xff0c;我们也会遇到一些常见的功能、模块&#xff0c;那么如何在原生HTML中使用组件化呢&am…

windows通过cmd终止线程

1、使用 netstat 命令查看特定端口的占用情况。例如&#xff0c;要查看端口号为 8080 的情况&#xff0c;可以执行以下命令&#xff1a; netstat -ano | findstr :9009这将显示所有占用端口 9009的网络连接&#xff0c;并列出 PID&#xff08;进程标识符&#xff09;。 2、终止…

Steam上线真人乙游,女性玩家还愿意买单吗?

Steam上线了一款真人乙游《糟糕&#xff01;他们太爱我了怎么办&#xff1f;》&#xff08;以下简称《糟糕&#xff01;&#xff09;。 乍一听这个游戏名&#xff0c;似乎和《完蛋&#xff01;我被美女包围了&#xff01;》有异曲同工之妙&#xff0c;事实也确实如此&#xff…