volatile

JMM和Volatile底层原理分析

雨燕双飞 提交于 2019-12-16 10:49:54
JMM和volatile分析 1.JMM:Java Memory Model,java线程内存模型 JMM:它是一个抽象的概念,描述的是线程和内存间的通信,java线程内存模型和CPU缓存模型类似,它是标准化的, 用于屏蔽硬件和操作系统对内存访问的差异性 。 2.JMM和8大原子操作结合 3.volatile的应用及底层原理探究 volatile : 轻量级的synchronized,在多处理器的开发中保证了共享变量的"可见性"。可见性的意思:当一个线程修改了某个共享变量时,其他使用到该共享变量的线程能够及时读取到修改的值。修饰得当,比synchronized的执行成本更低,因为它不会引起线程上下文切换和调度。 public class VolatileTest { private static volatile boolean flag = false; public static void main(String[] args) { update(); } public static void update(){ flag = true; System.out.println(flag); } } Volatile JIT编译器编译java代码为汇编指令查看 1.在jdk\jre\bin\ 目录下添加 hsdis-amd64.lib 2.在jdk1.8\jre\bin

单片机中断全局变量保护方法

℡╲_俬逩灬. 提交于 2019-12-15 14:28:40
首先要明白这几个知识点:关键字volatile的使用,原子操作,临界区的使用。明白的直接跳到文中的 4.全局变量的使用及保护 处查看。 1.关键字volatile 关键字volatile用于告诉编译器,说明被修身的变量可能会被意想不到地改变,防止编译器对代码进行优化。 比如如下程序: 1 ucNms=0x65;2 ucNms=0x66;3 ucNms=0x67;4 ucNms=0x68; 上述4条语句,如果变量在声明的时候(unsigned char ucNms;)没有使用volatile,那么编译器有可能对其优化,只编译最后一条语句ucNms=0x68;(即忽略前三条语句,只产生一条机器汇编代码);如果变量在声明的时候(volatile unsigned char ucNms;)使用了volatile,则编译器会逐一地进行编译并产生四条相应的机器代码(产生四条代码)。 精确地说就是,编译器在编译这个变量语句时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。所以下面几个情况在声明的时候需要用volatile关键字对其修饰: 1)并行设备的硬件寄存器(如:状态寄存器) 2)一个中断服务子程序中会访问到的非自动变量(Non-automatic variables) 3)多线程应用中被几个任务共享的变量 2.原子操作 原子操作可以理解为不被打断的操作

volatile关键字最详细介绍

别等时光非礼了梦想. 提交于 2019-12-15 12:45:00
目录 1 保证共享变量在多线程之间的可见性(内存可见性) 2 禁止指令重排 3 不保证原子性 1 保证共享变量在多线程之间的可见性(内存可见性) 如上图所示,所有线程的共享变量都存储在主内存中,每一个线程都有一个独有的工作内存,每个线程不直接操作在主内存中的变量,而是将主内存上变量的副本放进自己的工作内存中,只操作工作内存中的数据。当修改完毕后,再把修改后的结果放回到主内存中。每个线程都只操作自己工作内存中的变量,无法直接访问对方工作内存中的变量,线程间变量值的传递需要通过主内存来完成。 上述的Java内存模型在单线程的环境下不会出现问题,但在多线程的环境下可能会出现脏数据,例如:如果有AB两个线程同时拿到变量i,进行递增操作。A线程将变量i放到自己的工作内存中,然后做+1操作,然而此时,线程A还没有将修改后的值刷回到主内存中,而此时线程B也从主内存中拿到修改前的变量i,也进行了一遍+1的操作。最后A和B线程将各自的结果分别刷回到主内存中,看到的结果就是变量i只进行了一遍+1的操作,而实际上A和B进行了两次累加的操作,于是就出现了错误。究其原因,是因为线程B读取到了变量i的脏数据的缘故。 此时如果对变量i加上volatile关键字修饰的话,它可以保证当A线程对变量i值做了变动之后,会立即刷回到主内存中,而其它线程读取到该变量的值也作废,强迫重新从主内存中读取该变量的值

Java中Volatile关键字详解

我的未来我决定 提交于 2019-12-15 02:08:50
一、基本概念 先补充一下概念:Java 内存模型中的可见性、原子性和有序性。 可见性:   可见性是一种复杂的属性,因为可见性中的错误总是会违背我们的直觉。通常,我们无法确保执行读操作的线程能适时地看到其他线程写入的值,有时甚至是根本不可能的事情。为了确保多个线程之间对内存写入操作的可见性,必须使用同步机制。    可见性,是指线程之间的可见性,一个线程修改的状态对另一个线程是可见的。 也就是一个线程修改的结果。另一个线程马上就能看到。比如:用volatile修饰的变量,就会具有可见性。volatile修饰的变量不允许线程内部缓存和重排序,即直接修改内存。所以对其他线程是可见的。但是这里需要注意一个问题,volatile只能让被他修饰内容具有可见性,但不能保证它具有原子性。比如 volatile int a = 0;之后有一个操作 a++;这个变量a具有可见性,但是a++ 依然是一个非原子操作,也就是这个操作同样存在线程安全问题。   在 Java 中 volatile、synchronized 和 final 实现可见性。 原子性:    原子是世界上的最小单位,具有不可分割性。 比如 a=0;(a非long和double类型) 这个操作是不可分割的,那么我们说这个操作时原子操作。再比如:a++; 这个操作实际是a = a + 1;是可分割的,所以他不是一个原子操作

Java并发:volatile内存可见性和指令重排

隐身守侯 提交于 2019-12-15 00:34:23
volatile两大作用 1、保证内存可见性 2、防止指令重排 此外需注意volatile 并不保证操作的原子性。 (一)内存可见性 1 概念 JVM内存模型:主内存和线程独立的工作内存 Java内存模型规定,对于多个线程共享的变量,存储在主内存当中,每个线程都有自己独立的工作内存(比如CPU的寄存器),线程只能访问自己的工作内存,不可以访问其它线程的工作内存。 工作内存中保存了主内存共享变量的 副本 ,线程要操作这些共享变量,只能通过操作工作内存中的副本来实现,操作完毕之后再同步回到主内存当中。 如何保证多个线程操作主内存的数据完整性是一个难题,Java内存模型也规定了工作内存与主内存之间交互的协议,定义了8种原子操作: (1) lock:将主内存中的变量锁定,为一个线程所独占 (2) unclock:将lock加的锁定解除,此时其它的线程可以有机会访问此变量 (3) read:将主内存中的变量值读到工作内存当中 (4) load:将read读取的值保存到工作内存中的变量副本中。 (5) use:将值传递给线程的代码执行引擎 (6) assign:将执行引擎处理返回的值重新赋值给变量副本 (7) store:将变量副本的值存储到主内存中。 (8) write:将store存储的值写入到主内存的共享变量当中。 通过上面Java内存模型的概述,我们会注意到这么一个问题

【C】9.const和volatile分析

余生长醉 提交于 2019-12-14 19:45:39
const 关键字 const修饰的变量是只读的,本质还是变量 const修饰的局部变量在栈上分配空间 const修饰的全局变量在全局数据区分配空间 const只在编译期有用,在运行期无用 const修饰的变量不是真的常量,只是告诉编译器该变量不能出现在赋值符号的左边 const 全局变量的分歧 现代编译器中 (比如GCC),修改const全局变量将导致程序崩溃, 因为它存储于只读存储区(只读存储区的量不能修改) 注意: 在 标准C语言编译器 不会将const修饰的全局变量存储于只读存储区中,而是存储于可修改的全局数据区,其值依然可以改变(比如BCC编译器) #include <stdio.h> const int g_cc = 2; int main() { const int cc = 1; int* p = (int*)&cc; printf("cc = %d\n", cc); *p = 3; printf("cc = %d\n", cc); p = (int*)&g_cc; printf("g_cc = %d\n", g_cc); *p = 4; printf("g_cc = %d\n", g_cc); return 0; } 编译条件 gcc version 5.4.0 输出 cc = 1 cc = 3 g_cc = 2 Segmentation fault (core

CAS与原子类,MESI缓存一致性协议(Modified, Exclusive, Shared...

怎甘沉沦 提交于 2019-12-14 17:41:51
【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>> 原子类将CPU的CAS(Compare And Switch)指令封装起来,作为一项库级特性提供给应用程序开发者。但是CAS有ABA的问题。于是额外的AtomicStampedReference 被提供,用来提供带版本号的数据比较。可是CPU一次只能执行一条CAS指令,也就是说,它一次只能对一个内存地址做CAS操作,它要如何做到同时比较两个“数据”,即操作数与其版本,呢? 答案是:双字或多字CAS指令? ANYWAY... 再有就是,有CAS的效率是由MESI提高的。如果这么说,那么volatile做什么呢? 来源: oschina 链接: https://my.oschina.net/u/109289/blog/33358

Java并发中正确使用volatile

99封情书 提交于 2019-12-14 16:57:43
【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>> 前几天并发编程群里有同学对volatile的用法提出了疑问,刚好我记得Twitter有关实时搜索的这个 PPT 对这个问题解释的很清晰并有一个实际的应用场景,于是周末把这个问题摘录了一些和并发相关的内容如下: 目录: 并发 - 定义 悲观锁 - Pressimistic locking 乐观锁 - Optimistic locking 非阻塞算法 - Non-blocking algorithm 无锁算法 - Lock-free algorithm 无等待算法 - Wait-free algorithm Java的并发 Java内存模型 代码顺序规则 volatile变量规则 传递性 Safe publication案例 JSR-133 参考链接 并发 - 定义 悲观锁 - Pressimistic locking 一个线性在执行一个操作时持有对一个资源的独占锁。(互斥) 一般用在冲突比较可能发生的场景下 乐观锁 - Optimistic locking 尝试采用原子操作,而不需要持有锁;冲突可被检测,如果发生冲突,具有相应的重试逻辑 通常用在冲突较少发生的场景下 非阻塞算法 - Non-blocking algorithm 算法确保对线程间竞争共享资源时候,不会因为互斥而使任一线程的执行无限延迟; 无锁算法

CDI PostConstruct and volatile fields

浪子不回头ぞ 提交于 2019-12-14 03:55:50
问题 Using a post construct approach when we want to conditionally initialise some of the bean's fields, do we need to care about volatility of the field, since it is a multithread environment? Say, we have something like this: @ApplicationScoped public class FooService { private final ConfigurationService configurationService; private FooBean fooBean; @Inject FooService(ConfigurationService configurationService) { this.configurationService = configurationService; } void init(@Observes

Happens before between threads and atomic variable Part 2

倖福魔咒の 提交于 2019-12-14 03:09:19
问题 Since answer to Happens before between threads and atomic variable was that the asserts don't hold, I need an alternate implementation. Thread1 and Thread2 each update Integers t1 and t2 respectively. Once they are updated no other updates occur to t1 or t2. The values assigned to t1 and t2 come from a common counter which gets incremented after each assignment. I need to ensure the following asserts are true; int cnt=0; ReentrantLock lock = new ReentrantLock(); volatile Integer t1=null;