1.背景

volatile 修饰的作用????

什么是可见性??

什么是指令重排序??

2.可见性-案例

package com.my.aqs;

/**
* @Copyright (C) XXXXX技有限公司
* @Author: ldp
* @Date: 2023/4/28 9:10
* @Description: <p>
* volatile 的可见性代码演示
* </p>
*/
public class Volatile021Demo {
// 如果a 没有 被 volatile 修饰,这里的a是 [不可见的] ,[不可以] 读取到其他线下修改后的值, 即从[工作]内存中读取==> 产生死循环
// 如果a 被 volatile 修饰,这里的a是 [可见的] ,[可以]读取到其他线下修改后的值, 即从[主]内存中读取 ==> 不会产生死循环
// static volatile int a, b;
static int a, b; /**
* 指令重排序测试
*
* @param args
*/
public static void main(String[] args) throws InterruptedException {
// 线程A
Thread threadA = new Thread(() -> {
a = 1;
System.out.println("A执行完成:" + a);
});
// 线程B
Thread threadB = new Thread(() -> {
// 如果a 没有 被 volatile 修饰,这里的a是 [不可见的] ,[不可以] 读取到其他线下修改后的值, 即从[工作]内存中读取==> 产生死循环
// 如果a 被 volatile 修饰,这里的a是 [可见的] ,[可以]读取到其他线下修改后的值, 即从[主]内存中读取 ==> 不会产生死循环
while (a == 0) {
try {
// System.out.println("等待中===="); // 就算不添加volatile 修饰a, 执行输出语句后a会重新从主内存中读取
// System.out.println("当前a==>:" + a);
// Thread.sleep(500);// 就算不添加volatile 修饰a, 执行输sleep后a会重新从主内存中读取
b = a; // 不会导致从主内存中读取
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println("B执行完成:" + a);
});
threadB.start();
// 让B线程先执行
Thread.sleep(50);
threadA.start();
while (threadA.isAlive() || threadB.isAlive()) {
}
System.out.println("main执行完成:" + a);
}
}

3.避免指令重排序-案例

package com.my.aqs;

import java.util.HashSet;
import java.util.Set; /**
* @Copyright (C) XXXXX技有限公司
* @Author: ldp
* @Date: 2023/4/28 15:03
* @Description:
*/
public class Volatile03Demo {
// static volatile int a, b, A, B;
static int a, b, c, d; /**
* 指令重排序-案例演示
* <p>
* 如果:下面的代码,如果不考虑 指令重排序的问题, c和d永远都不会同时为0;
* 但是:因为在没有volatile修饰的情况下,可能会产生指令重排序,因此会产生 指令重排序,
* 导致
* t1线程中先执行 c = b;
* t2线程中先执行 d = a;
* 这两行代码先执行,从而导致c 和 d同时为0;
*
* @param args
* @throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
long num = 0;
Set<String> ABSet = new HashSet<>(8);
while (true) {
num++;
a = 0;
b = 0;
c = 0;
d = 0;
Thread t1 = new Thread(() -> {
a = 1;
c = b;
});
Thread t2 = new Thread(() -> {
b = 1;
d = a;
});
t1.start();
t2.start();
t1.join();
t2.join();
ABSet.add("a=" + a + "|b=" + b + "|c=" + c + "|d=" + d);
if (c == 0 && d == 0) {
System.out.println("a=" + a + "|b=" + b + "|c=" + c + "|d=" + d);
System.out.println("num=" + num);
System.out.println(ABSet);
break;
}
}
}
}

完美!

volatile重要特性-可见性,避免指令重排序-案例讲解的更多相关文章

  1. JVM并发机制的探讨——内存模型、内存可见性和指令重排序

    并发本来就是个有意思的问题,尤其是现在又流行这么一句话:“高帅富加机器,穷矮搓搞优化”. 从这句话可以看到,无论是高帅富还是穷矮搓都需要深入理解并发编程,高帅富加多了机器,需要协调多台机器或者多个CP ...

  2. 轻松学JVM(二)——内存模型、可见性、指令重排序

    上一篇我们介绍了JVM的基本运行流程以及内存结构,对JVM有了初步的认识,这篇文章我们将根据JVM的内存模型探索java当中变量的可见性以及不同的java指令在并发时可能发生的指令重排序的情况. 内存 ...

  3. JVM学习--(二)内存模型、可见性、指令重排序

    我们将根据JVM的内存模型探索java当中变量的可见性以及不同的java指令在并发时可能发生的指令重排序的情况. 内存模型 首先我们思考一下一个java线程要向另外一个线程进行通信,应该怎么做,我们再 ...

  4. 深入理解JVM(二)——内存模型、可见性、指令重排序

    上一篇我们介绍了JVM的基本运行流程以及内存结构,对JVM有了初步的认识,这篇文章我们将根据JVM的内存模型探索java当中变量的可见性以及不同的java指令在并发时可能发生的指令重排序的情况. 内存 ...

  5. 深入理解JVM一内存模型、可见性、指令重排序

    一.内存模型 首先我们思考一下一个java线程要向另外一个线程进行通信,应该怎么做,我们再把需求明确一点,一个java线程对一个变量的更新怎么通知到另外一个线程呢?我们知道java当中的实例对象.数组 ...

  6. 内存可见性,指令重排序,JIT。。。。。。从一个知乎问题谈起

    在知乎上看到一个问题<java中volatile关键字的疑惑?>,引起了我的兴趣 问题是这样的: package com.cc.test.volatileTest; public clas ...

  7. 关于volatile的可见性和禁止指令重排序的疑惑

    在学习volatile语义的可见性和禁止指令重排序的相关测试中,发现并不能体现出禁止指令重排序的特性 实验代码如下 package com.aaron.beginner.multithread.vol ...

  8. 使用 volatile 关键字保证变量可见性和禁止指令重排序

    volatile 概述 volatile 是 Java 提供的一种轻量级的同步机制.相比于传统的 synchronize,虽然 volatile 能实现的同步性要差一些,但开销更低,因为它不会引起频繁 ...

  9. Java的多线程机制系列:不得不提的volatile及指令重排序(happen-before)

    一.不得不提的volatile volatile是个很老的关键字,几乎伴随着JDK的诞生而诞生,我们都知道这个关键字,但又不太清楚什么时候会使用它:我们在JDK及开源框架中随处可见这个关键字,但并发专 ...

  10. Java的多线程机制系列:(四)不得不提的volatile及指令重排序(happen-before)

    一.不得不提的volatile volatile是个很老的关键字,几乎伴随着JDK的诞生而诞生,我们都知道这个关键字,但又不太清楚什么时候会使用它:我们在JDK及开源框架中随处可见这个关键字,但并发专 ...

随机推荐

  1. Spring扩展——@Import注解

    引言 在Spring中有许多Enable开头的注解,比如以下常见注解 @EnableTransactionManagement @EanbleAsync @EnableCache @EnableAsp ...

  2. Java代码规范及异常汇总 非空异常 NullPointerException

    Java规范及异常汇总1.java.lang.NullPointerException: nullorderReq.getId() != -1 修改为: orderReq.getId() != nul ...

  3. mklink命令使得OneDrive同步任意一个文件夹

      本文介绍利用mklink命令,使得OneDrive自动同步电脑中任意指定文件夹的方法.   OneDrive是由微软提供的云存储和文件同步服务.它提供了大量的云存储空间,允许用户将文件和数据存储在 ...

  4. 探索Semantic Kernel内置插件:深入了解ConversationSummaryPlugin的应用

    前言 经过前几章的学习我们已经熟悉了Semantic Kernel 插件的概念,以及基于Prompts构造的Semantic Plugins和基于本地方法构建的Native Plugins.本章我们来 ...

  5. 阿里云ECS主机自建SNAT,实现没有公网的主机通过有公网的主机访问外网

    目的: SNAT:实现没有公网IP的ECS实例借助有公网的ECS访问外网 实现前提: 有公网的主机与没有公网的主机必须处在同一个VPC安全组(确保两个主机互通才可以) 全程都在有公网的主机上操作 开启 ...

  6. vulnhub - hackme1

    vulnhub - hackme1 信息收集 端口扫描 详细扫描 目录扫描跟漏洞探测没发现什么可用信息,除了登录还有一个uploads目录应该是进入后台之后才能使用 web主页是个登录注册页面,爆了一 ...

  7. Java开发框架演变过程

    JavaWeb开发简史 Java框架创始人 Java框架说明 Spring: 把应用程序中的bean统一交给Spring进行管理控制,简化了我们的代码操作,和降低了代码的耦合度,Spring框架基本上 ...

  8. 详解Web应用安全系列(9)点击劫持

    点击劫持(Clickjacking)漏洞,也被称为界面伪装攻击(UI Redress Attack)或UI覆盖攻击,是一种利用视觉欺骗手段进行的网络攻击方式.这种攻击方式通过技术手段欺骗用户点击他们本 ...

  9. Java 面向对象编程之接口

    什么是接口? 是抽象方法的集合,接口通常以interface来声明,一个类通过继承接口的方式,从而来继承接口的抽象方法 语法 interface 名称 [extends 其他的接⼝名] { // 声明 ...

  10. 记一次 .NET某上位视觉程序 离奇崩溃分析

    一:背景 1. 讲故事 前段时间有位朋友找到我,说他们有一个崩溃的dump让我帮忙看下怎么回事,确实有太多的人在网上找各种故障分析最后联系到了我,还好我一直都是免费分析,不收取任何费用,造福社区. 话 ...