volatile

Think In Java 21.3.5 临界区

做~自己de王妃 提交于 2020-02-10 17:33:04
有时,你只是希望防止多个线程同时访问方法内部的部分代码而不是防止访问整个方法。通过这种方式分离出来的代码段被称为 临界区(critical section) ,它也使用synchronized关键字建立。这里,synchronized被用来指定某个对象,此对象的锁被用来对花括号内的代码进行同步控制: synchronized(syncObject){ // This code can be accessed by only one task at a time } 这也被称为 同步控制块 ;在进入此段代码前,必须得到syncObject对象的锁。如果其他线程已经得到这个锁,那么就得等到锁被释放以后,才能进入临界区。 通过使用同步控制块,而不是对整个方法进行同步控制,可以使多个任务访问对象的时间性能得到显著提高,下面的例子比较了这两种同步控制方法。此外,它也演示了如何把一个非保护类型的类,在其他类的保护和控制之下,应用于多线程的环境: package lime.tij._021._003._005; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.ExecutorService; import java.util

详解volatile在C++中的作用

泄露秘密 提交于 2020-02-10 07:41:04
volatile的介绍 volatile类似于大家所熟知的const也是一个类型修饰符。volatile是给编译器的指示来说明对它所修饰的对象不应该执行优化。volatile的作用就是用来进行多线程编程。在单线程中那就是只能起到限制编译器优化的作用。所以单线程的童鞋们就不用浪费精力看下面的了。 没有volatile的结果 如果没有volatile,你将无法在多线程中并行使用到基本变量。下面举一个我开发项目的实例(这个实例采用的是C#语言但不妨碍我们讨论C++)。在学校的一个.Net项目的开发中,我曾经在多线程监控中用到过一个基本变量Int32型的,我用它来控制多线程中监控的一个条件。考虑到基本变量是编译器自带的而且无法用lock锁上,我想当然的以为是原子操作不会有多线程的问题,可实际运行后发现程序的运行有时正常有时异常,改为用Dictionary对象处理并加锁以后才彻底正常。现在想来应该是多线程同时操作该变量了,具体的将在下面说清。 volatile的作用 如果一个基本变量被volatile修饰,编译器将不会把它保存到寄存器中,而是每一次都去访问内存中实际保存该变量的位置上。这一点就避免了没有volatile修饰的变量在多线程的读写中所产生的由于编译器优化所导致的灾难性问题。所以多线程中必须要共享的基本变量一定要加上volatile修饰符。当然了

STM32学习笔记——点亮LED

隐身守侯 提交于 2020-02-09 19:08:18
STM32学习笔记——点亮LED 本人学习STM32是直接通过操作stm32的寄存器,使用的开发板是野火ISO-V2版本; 先简单的介绍一下stm32的GPIO; stm32的GPIO有多种模式:   1.输入浮空   2.输入上拉   3.输入下拉   4.模拟输入   5.开漏输出   6.推挽式输出   7.推挽式复用功能   8.开漏复用功能 stm32GPIO模式设置相关寄存器设置的介绍 stm32中文参考手册中对GPIO模式设置对应寄存器的详细介绍: 下图为开发板LED的接线图; 根据上面的电路图可知,将GPIOB_0,GPIOF_7和GPIOF_8设置为低电平时,LED将被点亮; 程序代码: LED.h 文件 1 #ifndef __LED_H 2 #define __LED_H 3 4 void GPIO_Init(void); 5 6 7 8 9 #endif stm32.h 文件 1 #ifndef __STM32_H 2 #define __STM32_H 3 4 //引脚寄存器定义 5 6 //GPIO对应寄存器起始地址 7 8 #define GPIOA 0x40010800 9 #define GPIOB 0x40010C00 10 #define GPIOC 0x40011000 11 #define GPIOD 0x40011400 12

第一次开始尝试写,当记录自己的学习状态吧(学习驱动之史)

南楼画角 提交于 2020-02-07 09:46:31
#gec6818开发板之跑马灯 #今年寒假异常难过,不如我们一起来学习吧!这两天开始重新学习,突然感觉敲代码的日子可真美好,人都快憋坏咯 学习驱动的第一个关键,你得先知道开发板的启动过程,对于嵌入式Linux操作系统来说,先上电,然后进入到uboot中,加载Linux内核后,挂载根文件系统,最后才开始会执行自启动应用程序。 今天学的是如何让6818上的LED闪亮起来,在学过51单片机的基础上,对引脚之类的概念还是有些帮助的,但此次代码中却有了一个较大的区别,之前我们每次接触的C文件都会有一个头文件,以保证能成功调用各种库函数,但今天的学习内容我们用的是寄存器,来完成我们的任务,所以代码中没有任何头文件的出现。 怎么办呢,一个小白不知道接下来该怎么写了,直接码起来算了: //跑马灯 //1.定义寄存器 //D7->GPIOE13 #define GPIOEOUT (*(volatile unsigned int *)0xC001E000) #define GPIOEOUTENB (*(volatile unsigned int *)0xC001E004) #define GPIOEALTFN0 (*(volatile unsigned int *)0xC001E020) #define GPIOEALTFN1 (*(volatile unsigned int *)0xC001E024

Java重排序

笑着哭i 提交于 2020-02-07 01:35:23
之前听公司讲座说到的设计模式,经典的懒汉式单例模式会有重排序问题,当时不是很理解,后来深入学了JVM终于恍然大悟,这里做个总结分享。 重排序排序的就是操作指令的顺序,改变了指令的执行顺序。重排序首先要知道字节码.class文件,它就是JavaC编译后的那个字节码文件,它里面有操作指令的执行顺序,程序计数器就是根据字节码的操作指令的顺序进行寻址查找属性和方法进行操作。JVM会自行判断,把速度快的逻辑简单的代码先执行。 但是有的情况下,JVM会自己对执行指令进行一些优化,比如我们知道for循环重复读取一个值,它会直接从缓存中读取,这时候值就算发生改变JVM也没及时发现。就要加volatile关键字修饰那个属性值,volatile关键字简单来说,就是不让JVM进行优化。 重排序问题也是JVM做的优化,但是变成了好心做坏事。 比如单例模式下,我们都知道创建对象过程中,分配空间是在加载阶段,而里面有什么属性什么方法,都是初始化阶段才有的。JVM优化后就可能直接return了一个全部是null的只是分配了内存空间但是没有初始化的对象。 来看简单的懒汉式单例模式例子: public class Singleton { private static Singleton instance ; private Singleton ( ) { } public static synchronized

volatile的内存语义

痞子三分冷 提交于 2020-02-06 21:09:10
volatile的特征 ​ 理解volatile特征的一个好的办法是把volatile变量的单个读/写,看成是使用同一个锁对这些单个读/写做了同步。锁的happens-before规则保证释放锁和获取锁两个线程之间的内存可见性,这意味着对一个volatile变量的读总能看到任意线程对这个volatile变量最后的写入。 ​ 锁的内存语义决定了临界区代码的执行具有原子性,如果是多个volatile操作或者类似于volatile++这种符合操作,这些操作整体上不具有原子性。 ​ volatile变量自身具有下列特征: ​ 可见性:对一个volatile变量的读,总能看到任意线程对这个volatile变量的写。 ​ 原子性:对单个volatile变量的读/写具有原子性,复合操作不具有原子性。 从内存语义的角度来说,volatile的写-读与锁的释放-获取具有相同的内存效果。 volatile写的内存语义: ​ 当写一个volatile变量时,JMM会把该线程对应的本地内存中的共享变量值刷新到主内存。 volatile读的内存语义: ​ 当读一个volatile变量时,JMM会把该线程对应的本地内存置为无效。线程接下来将从主内存中读取共享变量。 volatile写和volatile读的内存语义总结: 线程A写一个volatile变量

Volatile关键字实现原理

可紊 提交于 2020-02-06 03:52:19
Volatile关键字实现原理 1、认识volatile关键字 程序举例 用一个线程读数据,一个线程改数据 存在数据的不一致性 2、机器硬件CPU与JMM (1)CPU Cache模型 程序的局部执行原理 (2)CPU缓存的一致性问题 解决方案: 1)总线加锁(粒度太大) 2)MESI() a. 读操作:不做任何事情,把Cache中的数据读到寄存器 b. 写操作:发出信号通知其他的CPU讲改变量的 Cache line 置为 无效 ,其他的CPU要访问这个变量的时候, 只能从内存 中获取。 Cache line CPU的cache中会增加很多的Cache line (3)Java内存模型 主存中的数据所有线程都可以访问(共享数据) 每个线程都有自己的工作空间,(本地内存)(私有数据) 工作空间数据:局部变量、内存的副本 线程不能直接修改内存中的数据,只能读到工作空间来修改,修改完成后刷新到内存 3、Volatile关键字的语义分析 volatile作用:让其他线程能够马上感知到某一线程多某个变量的修改 (1)保证可见性 对共享变量的修改,其他的线程马上能感知到 不能保证原子性 读、写、(i++) (2)保证有序性 重排序(编译阶段、指令优化阶段) 输入程序的代码顺序并不是实际执行的顺序 重排序后对单线程没有影响,对多线程有影响 Volatile Happens-before

volatile简介

强颜欢笑 提交于 2020-02-05 13:54:33
Volatile是java提供的 轻量级同步机制 ,比sychronized开销要小. 如果要使用 volatile 了,那肯定是在 多线程并发的环境下 (原子性、可见性、有序性).被volatile定义的变量,系统每次使用到它的时候都是直接从 主存中读取 ,而不是各个线程的工作内存. volatile适用于 多个变量之间 或者 某个变量当前值和修改之后值之间没有约束 。因此, 单独使用volatile还不足以实现计数器,互斥锁等 来源: CSDN 作者: 每天多学一点点. 链接: https://blog.csdn.net/JAVA_I_want/article/details/104180006

volatile修饰符

半世苍凉 提交于 2020-02-04 12:37:10
什么是volatile? 一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:   1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。   2)禁止进行指令重排序。 volatile 是一个类型修饰符。volatile 的作用是作为指令关键字,确保本条指令不会因编译器的优化而省略。 volatile 的特性 保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。(实现可见性) 禁止进行指令重排序。(实现有序性) volatile 只能保证对单次读/写的原子性。i++ 这种操作不能保证原子性。 volatile 保证多线程的可见性,首要要明白内存模型的相关概念: 大家都知道,计算机在执行程序时,每条指令都是在CPU中执行的,而执行指令过程中,势必涉及到数据的读取和写入。由于程序运行过程中的临时数据是存放在主存(物理内存)当中的,这时就存在一个问题,由于CPU执行速度很快,而从内存读取数据和向内存写入数据的过程跟CPU执行指令的速度比起来要慢的多,因此如果任何时候对数据的操作都要通过和内存的交互来进行,会大大降低指令执行的速度。因此在CPU里面就有了高速缓存。   也就是,当程序在运行过程中

Java并发机制的底层实现原理

為{幸葍}努か 提交于 2020-02-04 07:02:52
Java代码 编译之后 得到 Java字节码,被 类加载器加载到JVM中,最终 转化为汇编指令。 volatile volatile是轻量级的synchronized,被volatile修饰的变量,在一个线程能读到这个变量被另一个线程修改之后的值。 volatile不会引起线程上下文切换和调度。 volatile的两条实现原则 Lock前缀指令会引起处理器缓存回写到内存. 一个处理器的缓存回写到内存会导致其他处理器的缓存无效. synchronized实现同步 对于 普通同步方法,锁是 当前实例对象。 对于 静态同步方法,锁是 当前类的Class对象。 对于 同步方法块,锁是 Synchonized括号里配置的对象。 Synchonized在JVM里的实现原理 JVM 基于进入和退出Monitor对象来实现方法同步和代码块同步。 代码块同步是使用monitorenter和monitorexit指令实现的 方法同步是使用另外一种方式实现的,细节在JVM规范里并没有详细说明。但是,方法的同步同样可以使用monitorenter和monitorexit指令来实现。 monitorenter指令是在编译后插入到同步代码块的开始位置,monitorexit是插入到方法结束处和异常处。 JVM要保证每个monitorenter必须有对应的monitorexit与之配对。