为什么不使用volatile,其它线程也能得到当前线程修改后的值,不使用volatile也不存在可见性问题?原来解决可见性问题不一定需要volatile,println也可以
1. 为什么不使用volatile,其它线程也能得到变量修改后的值
实验代码分析:
①初始变量a=true,b=false;
②一个线程判断a或者b是否被改为相应逻辑,如果是,那么输出信息。
③修改a和b的线程。
实验结果分析:不是说没有volatile修饰的变量存在可见性问题吗,怎么可以得到另一个线程修改的值,不存在可见性问题吗??
原因:其实可见性问题的造成就是因为各自从缓存取数据,而不从内存取数据,如果缓存都没有数据,大家都使用内存的值,那么就不存在可见性问题。这里不存在可见性问题的原因就是当前变量还没有被放入缓存,我们可以加上一点休眠,让程序有时间把数据放入缓存,然后测试,如下。
其它博客有提到,说在线程中使用的睡眠会释放cpu执行权,然后CPU有时间去更新工作缓存和主存内容。那我这边通过一个简单的for循环,让CPU没有时间去同步缓存和主存。
2. 为什么不使用volatile,其它线程还能得到变量修改后的值
实验代码分析:
① 初始变量a=0,b=false;
②然后,一个线程判断 b 的值是否为false,是false那么循环输出“b is false and a is ”信息,直到 b 的值变为true,输出“b is true and a is”信息结束线程;
③然后延迟2ms,为了让后面的线程晚于前面线程执行;
④最后,另一个线程会修改a=1,b=true。
实验结果分析:首先控制台输出了一句“b is false and a is 0”,因为初始值a=0,b=false,所以正确;但是后面控制台输出了一句“b is true and a is 1”,为什么???不是说没有volatile修饰的变量是会存在可见性问题的吗?不是说一个线程修改的值,其它线程是得不到修改后的值吗??怎么这边能得到呢?
在分析之前,我们需要记住两点:第一,并发编程存在可见性问题;第二:可见性问题并不是只能通过volatile修饰来解决,也就是说——没有volatile修饰的变量不一定存在可见性问题。
原因:既然并发编程存在可见性问题,而且这边没有volatile修饰,那么可见性问题是怎么解决的呢?其实这边可见性问题是通过System.out.println语句解决的,也就是System.out.println语句触发了MESI缓存一致性协议。我们这边将System.out.println注释后,运行结果出现了可见性问题,可验证原先是System.out.println解决了可见性问题,运行结果及分析如下。
3. 其实System.out.println是通过synchronized关键字触发MESI缓存一致性协议,从而解决可见性问题,如下图。
总结:发生可见性问题,需要两个条件,①各线程操作数据是在缓存中操作,才会存在缓存不一致;②没有触发缓存一致性协议。
为什么不使用volatile,其它线程也能得到当前线程修改后的值,不使用volatile也不存在可见性问题?原来解决可见性问题不一定需要volatile,println也可以相关推荐
- python线程异常中断_中断线程
如果线程需要执行一个长时间任务,就可能需要能中断线程.中断线程就是其他线程给该线程发一个信号,该线程收到信号后结束执行run()方法,使得自身线程能立刻结束运行. 我们举个栗子:假设从网络下载一个10 ...
- Java多线程基础-6:线程安全问题及解决措施,synchronized关键字与volatile关键字
线程安全问题是多线程编程中最典型的一类问题之一.如果多线程环境下代码运行的结果是符合我们预期的,即该结果正是在单线程环境中应该出现的结果,则说这个程序是线程安全的. 通俗来说,线程不安全指的就是某一代 ...
- 一文教会你什么线程安全以及如何实现线程安全
title: 一文教会你什么线程安全以及如何实现线程安全 tags: 线程安全 Java并发 Java内存模型 synchronized volatile Lock 文章目录 一.线程安全的概念 二. ...
- 线程及同步的性能 – 线程池/ ThreadPoolExecutors/ ForkJoinPool
线程池和ThreadPoolExecutors 虽然在程序中可以直接使用Thread类型来进行线程操作,但是更多的情况是使用线程池,尤其是在Java EE应用服务器中,一般会使用若干个线程池来处理来自 ...
- 【Android 异步操作】线程池 ( 线程池 reject 拒绝任务 | 线程池 addWorker 添加任务 )
文章目录 一.线程池 reject 拒绝任务 二.线程池 addWorker 添加任务 在上一篇博客 [Android 异步操作]线程池 ( 线程池 execute 方法源码解析 ) 中 , 讲解 线 ...
- java——自己实现基础的线程池及带有任务数过多拒绝策略、线程池销毁、自动扩充线程数量及闲时自动回收线程等操作的改进版线程池
1. 实现第一版基础的线程池 1.1 首先我们定义一个线程池类ThreadPool,然后线程池有一个容器存放我们创建的线程,另一个容器则是存放当前线程池需要处理的任务队列,线程容器用ArrayList ...
- java 停止一个线程_Java如何停止一个线程
线程正常执行完毕,正常结束. 2.监视某些条件,直到某些条件成立,结束线程. class TestMyThread extends Thread { private volatile boolean ...
- C#中的多线程-线程同步基础 (控制线程数量)
同步要领 下面的表格列展了.NET对协调或同步线程动作的可用的工具: 简易阻止方法 构成 目的 Sleep 阻止给定的时间周期 Join 等待另一个线程完成 锁系统 构成 目的 跨进程? 速度 loc ...
- hashmap为什么线程不安全_什么时候线程不安全?怎样做到线程安全?怎么扩展线程安全的类?...
本文同名博客老炮说Java:https://www.laopaojava.com/,每天更新Spring/SpringMvc/SpringBoot/实战项目等文章资料 顺便再给大家推荐一套Spring ...
最新文章
- 1.3 Integer类详解
- Golang map输出排序
- Pwn环境配置(一)——安装虚拟机
- java调度:(六)quarts_cron表达式
- 如何在liferay ,struts2中跳转页面
- Java笔记-Spring Boot JDBC连接Oracle数据库
- Spark on Yarn遇到的几个问题
- java socket 客户端接收_java socket,怎么把客户端接收到的用户名和密码发送给后台?...
- java虚拟机家族种类
- 杰控连接mysql_杰控FameView在数据库连接和查询方面的应用———FameView组态软件在数据库处理方面的...
- eda交通灯控制器波形输入_EDA交通灯课程设计十字路口交通灯控制器设计.doc
- paypal android sdk,Android Paypal SDK错误:商家不接受此类付款
- 节点name在graph中无法展示_小节点 · 大奥秘│这正是你想学习的精妙休闲观景空间!(内含视频讲解)...
- scrapy 中 COOKIES_ENABLED 设置
- JS:dataTables实现跳转首页与尾页功能
- 0102Linux基础命令
- (详细易懂)一篇文章让你读懂到底什么是Ajax
- 洛谷_3975	[TJOI2015]弦论(后缀自动机)
- Linux驱动开发学习笔记【8】:Linux中断系统
- 《只是为了好玩:Linux之父林纳斯自传》读后感
热门文章
- SAP已发票校验采购订单退货 - 特殊业务
- WDA将改变现有的abap的开发方式
- ABAP 获取登陆者的IP地址和主机名
- oracle用dba登陆怎么登,以SQLDBA身份登录isqlplus
- redmine备份_Redmine 数据迁移记录
- oracle 快速上手,Oracle学习笔记:快速上手
- java 8 语法糖_Java8的lamada算是一种语法糖吗?
- java commons.util_Java — CommonUtil
- python保存创建文件报错 with open(fileName,‘w‘) as fp: IOError: [Errno 22] invalid mode (‘w‘) or filename
- 19道Python基础列表元祖的练习题