volatile

单例模式——我只有一个对象

与世无争的帅哥 提交于 2020-02-03 22:02:18
面试官:带笔了吧,那写两种单例模式的实现方法吧 沙沙沙刷刷刷~~~ 写好了 面试官:你这个是怎么保证线程安全的,那你知道,volatile 关键字? 类加载器?锁机制???? 点赞+收藏 就学会系列,文章收录在 GitHub JavaEgg ,N线互联网开发必备技能兵器谱 单例模式——独一无二的对象 单例模式,从我看 《Java 10分钟入门》那天就听过的一个设计模式,还被面试过好几次的设计模式问题,今天一网打尽~~ 有一些对象我们确实只需要一个,比如,线程池、数据库连接、缓存、日志对象等,如果有多个的话,会造成程序的行为异常,资源使用过量或者不一致的问题。你也许会说,这种我用全局变量不也能实现吗,还整个单例模式,好像你很流弊的样子,如果将对象赋值给一个全局变量,那程序启动就会创建好对象,万一这个对象很耗资源,我们还可能在某些时候用不到,这就造成了资源的浪费,不合理,所以就有了单例模式。 单例模式的定义 单例模式确保一个类只有一个实例,并提供一个全局唯一访问点 单例模式的类图 单例模式的实现 饿汉式 static 变量在类装载的时候进行初始化 多个实例的 static 变量会共享同一块内存区域 用这两个知识点写出的单例类就是饿汉式了,初始化类的时候就创建,饥不择食,饿汉 public class Singleton { //构造私有化,防止直接new private

Java内存模型与线程(二)

一曲冷凌霜 提交于 2020-02-03 04:44:24
时间记录:2020-2-1 上章节了解到了关于内存的一些操作和简单的规则,在其中volatile属于一个比较特殊的内容的操作,而也存在一些特殊的变量的内存操作的特殊性, long , double 的操作的特殊性,但是其表现没有什么差异。 Volatile型变量的特殊规则 在java中volatile为一个关键字,是一种轻量级的同步机制,但是其在一些的特定场景下的操作比较合适,不是完全的同步,其只是对所有线程是 可见的 ,其实际上的意义是线程在使用被其修饰的变量的时候一定是先从主内存中进行同步,然后再进行使用。 volatile的几个特性 1:被此修饰的变量对所有线程的可见性,这里的 可见性 是指当一条线程修改看这个变量的值,新值对于其他线程来说是可以立即得知的。(注意:这里的立即得知其实是对变量的使用定下了规则,必须从主内存中进行获取) 2:被此修饰的变量在 发生改变 的时候得马上返回到主内存,也就是进行同步的操作 3:禁止指令排序优化(这个在jdk1.5中才完全被修复,关于被修饰的禁止指令排序优化) 指令重排序 是指cpu采用了允许将多条指令不安程序规定的顺序分开发送个各相应电路单元出路(这里应该是指集成的寄存器,个人猜测) 常见的误解 【volatile变量对所有线程是立即可见的,对volatile变量所有的写操作都能立刻反应到其它线程之中,换句话说

Java内存模型与线程(三)

那年仲夏 提交于 2020-02-02 15:35:38
时间记录:202-2-2 上章节主要了解volatile的使用和一些细节部分操作,下面主要为long和double变量的一些特殊规则,还有就是java内存模型的一些特性吧。 long和double变量的一些特殊操作 long和double都是64位的,在java虚拟机中有一条宽松的规定: 允许虚拟机将没有被volatile修饰的64位数据的读写操作划分为两次32位操作来进行 。之前说到对变量的操作的原子性,这样的情况即是允许虚拟机实现选择可以不保证64位数据类型的load,store,read和write着四个操作的原子性,这个就是 非原子性协定 ,那么在多线程读取的情况下就可能会读取到一个半值,这个目前我没碰到过出现这种情况,大部分都认为其实原子的。注意下这个问题就可以了,以后如果遇到要想起。 java内存模型的特性 之前已经了解java内存模型中的变量的访问规则,然后其主要是围绕的 原子性 , 可见性 , 有序性 来建立的。 一:原子性 由java内存模型直接保证的原子性变量操作包括read,load,assign,use,store,write,我们大致可以认为基本数据类型的访问读写是具备原子性的(double,long除外,但是这种基本上不会发生的情况,我们不去考虑了)。我们常说的原子操作,就是说一个操作过程中是独立的,不会受到外面的干扰,在java中也提供了字节指令

volatile关键字总结

余生颓废 提交于 2020-02-01 03:32:15
Java内存模型 主内存 (Main Memory) 主内存可以简单理解为 计算机当中的内存 , 但又不完全等同. 主内存被所有的线程 共享 , 对于一个共享变量来说, 主内存当中存储了它的 “本尊”. 工作内存 (Working Memory) 工作内存可以理解为CPU中的 高速缓存 , 每一个线程拥有自己的工作内存, 对于一个共享变量来说, 工作内存中存储了它的 “副本”. 线程对共享变量的所有操作 必须 在工作内存上进行, 不能直接读写主内存的变量, 不同线程之间也无法访问彼此的工作内存, 变量值的传递只能通过主内存来进行. 所以就产生了主内存和工作内存之间可能会有很小的一段时间不同步的问题. 不同步的例子 对于一个静态变量 : static int s = 0 ; 线程A : s = 3 ; 则JMM的工作流程如下所示: 第一步: 先在主内存中 创建 共享变量s 第二步: 线程A读进工作内存中, 进行修改 第三步: 再将修改后的共享变量的值赋给主内存 从单线程的角度来讲, 这一系列过程没有任何问题. 这时候我们引入线程B, 执行如下代码: System . out . println ( "s=" + s ) ; 这个时候, 在多线程环境下, 输出的结果可能是 0 或 3. 上图中的第三步完成时读入 上图中的第二步之后, 第三步赋值之前读入 (主内存中还是0)

java 线程之间是如何通信的

安稳与你 提交于 2020-02-01 01:06:27
java线程之间的通信方式总共有 8 种,分别是 volatile、synchronized、interrupt、wait、notify、notifyAll、join、管道输入/输出 , 我们一个一个的来说明! 1.volatile 线程会将内存中的数据,拷贝到各自的本地内存中( 这里的本地内存指的是 cpu cache ( 比如 CPU 的一级缓存、二级缓存等 ),寄存器)。当某个变量被 volatile 修饰并且发生改变时,volatile 变量底层会通过 lock前缀的指令,将该变量写会主存,同时利用 缓存一致性协议,促使其他线程的本地变量的数据无效,从而再次直接从主存读取数据。 代码演示: java 如何优雅的停止一个线程 2.synchronized monitor可以理解为一个同步工具,成功则获得了对象的锁,失败,则进入同步队列进行等待 代码演示: java 如何优雅的停止一个线程 3. interrupt 代码演示: java 如何优雅的停止一个线程 4. wait、notify、notifyAll 代码演示: /** * @author shengjk1 * @date 2019/8/29 */ /* 等待/通知的经典范式 */ public class WaitNotify { static boolean flag = true; static Object

C++中关键字volatile和mutable用法

廉价感情. 提交于 2020-01-31 12:48:14
C/C++中的volatile关键字和const对应,用来修饰变量,用于告诉编译器该变量值是不稳定的,可能被更改。使用volatile注意事项: (1). 编译器会对带有volatile关键字的变量禁用优化(A volatile specifier is a hint to a compiler that an object may change its value in ways not specified by the language so that aggressive optimizations must be avoided)。 (2). 当多个线程都要用到某一个变量且该变量的值会被改变时应该用volatile声明,该关键字的作用是防止编译器优化把变量从内存装入CPU寄存器中。如果变量被装入寄存器,那么多个线程有可能有的使用内存中的变量,有的使用寄存器中的变量,这会造成程序的错误执行。volatile的意思是让编译器每次操作该变量时一定要从内存中取出,而不是使用已经存在寄存器中的值(It cannot cache the variables in register)。 (3). 中断服务程序中访问到的变量最好带上volatile。 (4). 并行设备的硬件寄存器的变量最好带上volatile。 (5). 声明的变量可以同时带有const和volatile关键字。 (6)

01-021【jvm】聊聊volatile

我只是一个虾纸丫 提交于 2020-01-31 03:15:56
volatile 概念:是java虚拟机提供的轻量级的同步机制 性质:保证可见性;不保证原子性;禁止指令重排 涉及: JMM . 1. 保证可见性 验证volatile的可见性 假如int number = 0;number变量之前根本没有添加volatile关键字修饰,则 没有通知main线程number的修改,所以不会退出循环 package com . magic . juc0117 ; import java . util . concurrent . TimeUnit ; class MyData { //添加volatile关键字修饰后,number修改其他线程立即可见 volatile int number = 0 ; public void addTo60 ( ) { this . number = 60 ; } public void addPlusPlus ( ) { this . number ++ ; } AtomicInteger atomicInteger = new AtomicInteger ( ) ; public void addAtomic ( ) { atomicInteger . getAndIncrement ( ) ; } } public class VolatileDemo { public static void main (

Java并发编程实践笔记

对着背影说爱祢 提交于 2020-01-30 11:09:15
1, 保证线程安全的三种方法 : a, 不要跨线程访问共享变量 b, 使共享变量是 final类型的 c, 将共享变量的操作加上同步 2, 一开始就将类设计成线程安全的 , 比在后期重新修复它 ,更容易 . 3, 编写多线程程序 , 首先保证它是正确的 , 其次再考虑性能 . 4, 无状态或只读对象永远是线程安全的 . 5, 不要将一个共享变量裸露在多线程环境下 (无同步或不可变性保护 ) 6, 多线程环境下的延迟加载需要同步的保护 , 因为延迟加载会造成对象重复实例化 7, 对于 volatile 声明的数值类型变量进行运算 , 往往是不安全的 (volatile 只能保证可见性 , 不能保证原子性 ). 详见 volatile 原理与技巧中 , 脏数据问题讨论 . 8, 当一个线程请求获得它自己占有的锁时 ( 同一把锁的嵌套使用 ), 我们称该锁为可重入锁 . 在 jdk1.5 并发包中 , 提供了可重入锁的 java 实现 -ReentrantLock. 9, 每个共享变量 , 都应该由一个唯一确定的锁保护 . 创建与变量相同数目的 ReentrantLock, 使他们负责每个变量的线程安全 . 10,虽然缩小同步块的范围 , 可以提升系统性能 . 但在保证原子性的情况下 , 不可将原子操作分解成多个 synchronized块 . 11, 在没有同步的情况下 ,

JZ2440裸机点亮LED【学习笔记】

痞子三分冷 提交于 2020-01-30 05:45:23
平台:jz2440 作者:庄泽彬 (欢迎转载,请注明作者) 说明:韦东山一期视频学习笔记 一、我们首先来做第一个实验,用汇编语言点亮板子上的LED。 1.1 LED的原理图 从下面的原理图可知LED1是连接到芯片的GPF4 1.2 相关的GPIO寄存器的配置 我们要点亮LED,就要把相关的端口配置成输出口,并且输出低电平。看看芯片手册,要GPF4输出低电平要配置GPFCON寄存器设置相应的位位01即为输出状态,在配置GPFDAT相应的位为0即可输出低电平。 1.3相关代码: led_on.S文件 1 .text 2 .global _start 3 _start: 4 LDR R0,=0x56000050 @ 设置R0为GPFCON寄存器 5 @ 用于配置端口的输入、输出状态 6 7 mov R1,#0x00000100 8 str R1,[R0] @ 设置GPF4端口为输出口 9 10 ldr R0,=0x56000054 @ 设置R0为GPFDAT寄存器 11 @ 用于配置端口输出的高低电平 12 13 mov R1,#0x00000100 14 str R1,[R0] @ 输出低电平 15 16 MAIN_LOOP: 17 B MAIN_LOOP Makefile文件 1 led_on.bin:led_on.S 2 arm-linux-gcc -g -c -o led_on

Volatile关键字实现原理

混江龙づ霸主 提交于 2020-01-29 21:36:56
1、 认识 volatile 关键字 volatile是java提供的一种同步手段,只不过它是轻量级的同步,为什么这么说,因为volatile只能保证多线程的内存可见性,不能保证多线程的执行有序性。而最彻底的同步要保证有序性和可见性,例如synchronized。任何被volatile修饰的变量,都不拷贝副本到工作内存,任何修改都及时写在主存。因此对于volatile修饰的变量的修改,所有线程马上就能看到,但是volatile不能保证对变量的修改是有序的。 程序的局部执行原理 Java内存模型 jvm将内存组织为主内存和工作内存两个部分。 主内存主要包括本地方法区和堆。每个线程都有一个工作内存,工作内存中主要包括两部分,一个是属于该线程私有的栈,另一个是对主存部分变量拷贝的寄存器(包括程序计数器PC和cpu工作的高速缓存区) 1) 主存中的数据所有线程都可以访问(共享数据) 2) 每个线程都有自己的工作空间,(本地内存)(私有数据) 3) 工作空间数据:局部变量、内存的副本 4) 线程不能直接修改内存中的数据,只能读到工作空间来修改,修改完成后刷新到内存 Volatile 关键字的语义分析    volatile作用:让其他线程能够马上感知到某一线程多某个变量的修改 (1)保证可见性 对共享变量的修改,其他的线程马上能感知到 不能保证原子性 读、写、( i++) (2)保证有序性