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

Volatile的内存语义

1、volatile的特性

可见性:对一个volatile变量的读,总能够看到任意一个线程对这个volatile变量的写入。

原子性:对任意单个volatile变量的读/写具有原子性,但类似于volatile++这种复合操作不具有原子性。

接下来我们用程序验证。


public class OldVolatileFeaturesExample {volatile long v1 = 0L;      // 使用volatile 声明64位的long型变量//long v1 = 0L;public void set(long l){v1 = l;                 //单个volatile 变量的写}public void getAndIncrement(){v1++;                   // 多个volatile 变量的读/写}public long get(){return v1;              //  单个volatile 变量的读}public static void main(String[] args) {final OldVolatileFeaturesExample volatileFeaturesExamlple = new OldVolatileFeaturesExample();Thread thread0 = new Thread(new Runnable() {public void run() {volatileFeaturesExamlple.set(1L);}});thread0.start();Thread thread1 = new Thread(new Runnable() {public void run() {volatileFeaturesExamlple.getAndIncrement();}});thread1.start();Thread thread2 = new Thread(new Runnable() {public void run() {long l = volatileFeaturesExamlple.get();System.out.println("创建的l值-------"+ l);}});thread2.start();/*        for (int i = 0; i < 10; i++) {Thread thread0 = new Thread(new Runnable() {public void run() {volatileFeaturesExamlple.set(1L);}});thread0.start();Thread thread1 = new Thread(new Runnable() {public void run() {volatileFeaturesExamlple.getAndIncrement();}});thread1.start();Thread thread2 = new Thread(new Runnable() {public void run() {long l = volatileFeaturesExamlple.get();System.out.println("创建的l值-------"+ l);}});thread2.start();}*/}}

这里,线程thread0 设置使用volatile修饰的long类型变量 v1 ;线程thread1 进行v1++操作, thread2 获取变量v1的值,并打印结果。那么 v1的值是几呢?

上面这段程序运行结果是:

创建的l值-------2

那么就算不用volatile修饰的v1变量,也执行上述操作,结果会是什么样子呢?没错,还是2。

那么使用volatile修饰的v1变量 当使用for 循环呢?也就是多个volatile变量的读写操作的结果:


创建的l值-------2
创建的l值-------2
创建的l值-------1
创建的l值-------1
创建的l值-------1
创建的l值-------2
创建的l值-------3
创建的l值-------1
创建的l值-------2
创建的l值-------3

假设具有原子性,那么v1循环加10次 1,那么它的结果应该是 10,而不是上面的结果。上面的程序等价于:

public class NewVolatileFeaturesExample {long v1 = 0L;public synchronized void set(long l){  //对单个的普通变量的写用同一个锁同步v1 = l;}public void getAndIncrement(){         //普通方法调用long temp = get();                 //调用已同步的读方法temp += 1L;                        //普通写操作set(temp);                         //调用已同步的写方法}public synchronized long get(){         // 对单个的普通变量的读用同一个锁同步return v1;}public static void main(String[] args) {final NewVolatileFeaturesExample newVolatileFeaturesExample = new NewVolatileFeaturesExample();/*        for (int i = 0; i < 10; i++) {Thread thread0 = new Thread(new Runnable() {public void run() {newVolatileFeaturesExample.set(1L);}});thread0.start();Thread thread1 = new Thread(new Runnable() {public void run() {newVolatileFeaturesExample.getAndIncrement();}});thread1.start();Thread thread2 = new Thread(new Runnable() {public void run() {long l = newVolatileFeaturesExample.get();System.out.println("创建的l值-------"+ l);}});thread2.start();}*/Thread thread0 = new Thread(new Runnable() {public void run() {newVolatileFeaturesExample.set(1L);}});thread0.start();Thread thread1 = new Thread(new Runnable() {public void run() {newVolatileFeaturesExample.getAndIncrement();}});thread1.start();Thread thread2 = new Thread(new Runnable() {public void run() {long l = newVolatileFeaturesExample.get();System.out.println("创建的l值-------"+ l);}});thread2.start();}
}

这个也就是相当于对v1变量的读和写进行了synchronized 同步锁操作。

而锁的语义决定了临界区代码的执行具有原子性。锁的happens-before 规则保证了释放锁和获取锁的两个线程之间的内存可见性。那么volatile 写和读建立的happens-before 关系是又是什么样子呢?欲知后事如何,请看下回分解。

更多创作在我的公众号里哦。
在这里插入图片描述

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 基于地理坐标的高阶几何编辑工具算法(4)——线分割面
  • 一周开发一个在线客服系统
  • 实现信号发生控制
  • IDEA中一些常见操作【持续更新】
  • echarts-树图、关系图、桑基图、日历图
  • C++ Primer (第五版)第九章习题部分答案
  • 【openpcdet中yaml文件的DATA_AUGMENTOR学习】
  • vue...
  • 二叉树基于队列实现的操作详解
  • python梯度下降法求解三元线性回归系数,并绘制结果
  • EyeMock下载与使用教程
  • 【C++项目】实时聊天的在线匹配五子棋对战游戏
  • in 和exists的区别
  • DHCP简介
  • 探索亚马逊云科技技术课程:大模型平台与提示工程的应用与优化
  • php的引用
  • hexo+github搭建个人博客
  • [译]Python中的类属性与实例属性的区别
  • JavaScript设计模式之工厂模式
  • MaxCompute访问TableStore(OTS) 数据
  • Netty+SpringBoot+FastDFS+Html5实现聊天App(六)
  • Nginx 通过 Lua + Redis 实现动态封禁 IP
  • pdf文件如何在线转换为jpg图片
  • PHP 使用 Swoole - TaskWorker 实现异步操作 Mysql
  • vue--为什么data属性必须是一个函数
  • windows-nginx-https-本地配置
  • 得到一个数组中任意X个元素的所有组合 即C(n,m)
  • 反思总结然后整装待发
  • 基于web的全景—— Pannellum小试
  • 解析带emoji和链接的聊天系统消息
  • 学习使用ExpressJS 4.0中的新Router
  • ​​​​​​​GitLab 之 GitLab-Runner 安装,配置与问题汇总
  • ​MPV,汽车产品里一个特殊品类的进化过程
  • ## 基础知识
  • #【QT 5 调试软件后,发布相关:软件生成exe文件 + 文件打包】
  • (1)SpringCloud 整合Python
  • (BAT向)Java岗常问高频面试汇总:MyBatis 微服务 Spring 分布式 MySQL等(1)
  • (C#)Windows Shell 外壳编程系列4 - 上下文菜单(iContextMenu)(二)嵌入菜单和执行命令...
  • (C#)一个最简单的链表类
  • (C++)栈的链式存储结构(出栈、入栈、判空、遍历、销毁)(数据结构与算法)
  • (ZT)北大教授朱青生给学生的一封信:大学,更是一个科学的保证
  • (八)Flask之app.route装饰器函数的参数
  • (数据结构)顺序表的定义
  • (四)React组件、useState、组件样式
  • (算法)前K大的和
  • (原創) 如何刪除Windows Live Writer留在本機的文章? (Web) (Windows Live Writer)
  • .NET 8.0 中有哪些新的变化?
  • .NET C#版本和.NET版本以及VS版本的对应关系
  • .Net 执行Linux下多行shell命令方法
  • .NET/C# 使用反射调用含 ref 或 out 参数的方法
  • .Net调用Java编写的WebServices返回值为Null的解决方法(SoapUI工具测试有返回值)
  • .NET技术成长路线架构图
  • .Net面试题4
  • .NET设计模式(11):组合模式(Composite Pattern)
  • .set 数据导入matlab,设置变量导入选项 - MATLAB setvaropts - MathWorks 中国