原子

Java面试官最爱问的volatile关键字

血红的双手。 提交于 2019-12-29 23:11:16
在Java的面试当中,面试官最爱问的就是volatile关键字相关的问题。经过多次面试之后,你是否思考过,为什么他们那么爱问volatile关键字相关的问题?而对于你,如果作为面试官,是否也会考虑采用volatile关键字作为切入点呢? 为什么爱问volatile关键字 爱问volatile关键字的面试官,大多数情况下都是有一定功底的,因为volatile作为切入点,往底层走可以切入Java内存模型(JMM),往并发方向走又可接切入Java并发编程,当然,再深入追究,JVM的底层操作、字节码的操作、单例都可以牵扯出来。 所以说懂的人提问题都是有门道的。那么,先整体来看看volatile关键字都设计到哪些点:内存可见性(JMM特性)、原子性(JMM特性)、禁止指令重排、线程并发、与synchronized的区别……再往深层次挖,可能就涉及到字节码、JVM等。 不过值得庆幸的是,如果你已经学习了微信公众号“程序新视界”JVM系列的文章,上面的知识点已经不是什么问题了,权当是复习了。那么,下面就以面试官提问的形式,在不看答案的情况下,尝试回答,看看学习效果如何。夺命连环问,开始…… 面试官:说说volatile关键字的特性 被volatile修饰的共享变量,就具有了以下两点特性: 保证了不同线程对该变量操作的内存可见性; 禁止指令重排序; 回答的很好,点出了volatile关键字两大特性

对volatile不具有原子性的理解

随声附和 提交于 2019-12-29 20:34:56
在阅读多线程书籍的时候,对volatile的原子性产生了疑问,问题类似于这篇 文章 所阐述的那样。经过一番思考给出自己的理解。 我们知道对于可见性,Java提供了volatile关键字来保证 可见性 、 有序性 。 但不保证原子性 。 普通的共享变量不能保证可见性,因为普通共享变量被修改之后,什么时候被写入主存是不确定的,当其他线程去读取时,此时内存中可能还是原来的旧值,因此无法保证可见性。   背景:为了提高处理速度,处理器不直接和内存进行通信,而是先将系统内存的数据读到内部缓存(L1,L2或其他)后再进行操作,但操作完不知道何时会写到内存。 如果对声明了volatile的变量进行写操作 ,JVM就会向处理器发送一条指令,将这个变量所在缓存行的数据写回到系统内存。但是,就算写回到内存,如果其他处理器缓存的值还是旧的,再执行计算操作就会有问题。 在多处理器下,为了保证各个处理器的缓存是一致的,就会 实现缓存一致性协议 ,每个处理器通过嗅探在总线上传播的数据来检查自己缓存的值是不是过期了,当处理器发现自己缓存行对应的内存地址被修改,就会将当前处理器的缓存行设置成无效状态,当处理器对这个数据进行修改操作的时候,会重新从系统内存中把数据读到处理器缓存里。 总结下来 : 第一:使用volatile关键字会强制将修改的值立即写入主存; 第二:使用volatile关键字的话,当线程2进行修改时

易失性与联锁对抗锁定

喜你入骨 提交于 2019-12-29 19:40:19
【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>> 假设一个类有一个由多个线程访问的 public int counter 字段。 此 int 仅递增或递减。 要增加此字段,应使用哪种方法,为什么? lock(this.locker) this.counter++; , Interlocked.Increment(ref this.counter); , 将 counter 的访问修饰符更改为 public volatile 。 既然我发现了 volatile ,我一直在删除许多 lock 语句和 Interlocked 的使用。 但是有理由不这样做吗? #1楼 我是第二个Jon Skeet的回答,并希望为想要了解更多关于“volatile”和Interlocked的人们添加以下链接: 原子性,波动性和不变性是不同的,第一部分 - (Eric Lippert的编码中的神话般的冒险) 原子性,波动性和不变性是不同的,第二部分 原子性,波动性和不变性是不同的,第三部分 Sayonara Volatile - (2012年出现的Joe Duffy博客的Wayback Machine快照) #2楼 互锁功能不会锁定。 它们是原子的,这意味着它们可以完成而不会在增量期间进行上下文切换。 所以没有死锁或等待的可能性。 我会说你应该总是喜欢锁定和增量。

化学-分子间作用力:百科

淺唱寂寞╮ 提交于 2019-12-29 07:16:10
ylbtech-化学-分子间作用力:百科 分子间作用力,又称范德瓦尔斯力(van der Waals force)。是存在于中性分子或原子之间的一种 弱碱性 的电性吸引力。分子间作用力(范德瓦尔斯力)有三个来源:① 极性分子 的永久 偶极矩 之间的相互作用。②一个极性分子使另一个分子极化,产生诱导偶极矩并相互吸引。③分子中电子的运动产生瞬时偶极矩,它使临近分子瞬时 极化 ,后者又反过来增强原来分子的瞬时偶极矩;这种相互耦合产生静电吸引作用,这三种力的贡献不同,通常第三种作用的贡献最大。 分子间作用力只存在于 分子 (molecule)与分子之间或 惰性气体 (noble gas) 原子 (atom)间的作用力,又称范德华力(van der waals),具有 加和性 ,属于 次级键 。 氢键 (hydrogen bond)、弱 范德华力 、 疏水 作用力、芳环堆积作用、 卤键 都属于 次级键 (又称分子间弱相互作用)。 1. 返回顶部 1、 中文名:分子间作用力 外文名:intermolecular force 别 名:范德华力,范氏力 作用对象:分子之间 高分子化合物内官能团 一般分类: 范德华力 、 氢键 、其他非共价键 来源分类: 色散力 , 取向力 , 诱导力 ,其他 归 属:化学,力,分子间力 目录 1 氢键 2 作用力分类 ▪ 色散力 ▪ 诱导力 ▪ 取向力 ▪

java内存模型-锁

▼魔方 西西 提交于 2019-12-29 03:13:52
锁的释放-获取建立的 happens before 关系 锁是 java 并发编程中最重要的同步机制。锁除了让临界区互斥执行外,还可以让释放锁的线程向获取同一个锁的线程发送消息。下面是锁释放-获取的示例代码: class MonitorExample { int a = 0; public synchronized void writer() { //1 a++; //2 } //3 public synchronized void reader() { //4 int i = a; //5 …… } //6 } 假设线程 A 执行 writer() 方法,随后线程 B 执行 reader() 方法。根据 happens before 规则,这个过程包含的 happens before 关系可以分为两类: 根据程序次序规则,1 happens before 2, 2 happens before 3; 4 happens before 5, 5 happens before 6。 根据监视器锁规则,3 happens before 4。 根据 happens before 的传递性,2 happens before 5。 上述 happens before 关系的图形化表现形式如下: 在上图中,每一个箭头链接的两个节点,代表了一个 happens before 关系

JAVA内存模型5-锁

只谈情不闲聊 提交于 2019-12-29 03:12:52
锁的释放-获取建立的happens before关系 锁是java并发编程中最重要的同步机制。锁除了让临界区互斥执行外,还可以让释放锁的线程向获取同一个锁的线程发送消息。下面是锁释放-获取的示例代码: class MonitorExample { int a = 0; public synchronized void writer() { //1 a++; //2 } //3 public synchronized void reader() { //4 int i = a; //5 …… } //6 } View Code   假设线程A执行writer()方法,随后线程B执行reader()方法。根据happens -before规则,这个过程包含的happens -before关系可以分为两类: 根据监视器锁规则,3happens before4。 根据程序次序规则,1happens -before2, 2 happens- before 3; 4 happens- before 5, 5 happens -before 6。 根据happens before 的传递性,2 happens before 5。    上述happens -before关系的图形化表现形式如下:   在上图中,每一个箭头链接的两个节点,代表了一个happens before关系

原子操作和volatile关键字

跟風遠走 提交于 2019-12-29 02:35:57
原子操作 :不可被中断的操作。要么全执行,要么全不执行。 现代CPU读取内存,通过读取缓存再写入主存。先去主存读--->写入缓存---->运行线程--->写入缓存---->写入主存 多cpu时会出现缓存一致性和总线锁的问题。 只有简单的读取,赋值操作,即一步完成的操作才是原子操作。 volatile,synchronized,lock 能保证可见性, volatile保证修改的值立即更新到主存,synchronized和lock保证同一时刻只有一个线程操作变量,在锁被释放前会将新值写入内存。 线程的有序性: java内存模型具备一些先天的有序性,即 happensbefore(先行发生)原则 : 1,程序次序规则,一个线程内,按照代码书写顺序执行 2,锁定规则,一个解锁操作ounlock先行发生于后面对同一个锁的lock操作 3,volatile变量规则,对一个变量的写操作先行发生于后面对这个变量的读操作 4,传递规则,A先发生于B,B先发生于C,则A先发生于C 5,线程启动规则,Thread对象的start()方法先行发生于此线程的每一个操作 6,线程中断规则,对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生,即中断的发生先于中断被检测到 7,线程终结规则,线程中所有的操作都先行发生于线程的中止检测,可以通过Thread.join()方法结束

单核,多核CPU的原子操作

不羁岁月 提交于 2019-12-29 02:35:30
一. 何谓"原子操作": 原子操作就是: 不可中断的一个或者一系列操作, 也就是不会被线程调度机制打断的操作, 运行期间不会有任何的上下文切换(context switch). 二. 为什么关注原子操作? 1. 如果确定某个操作是原子的, 就不用为了去保护这个操作而加上会耗费昂贵性能开销的锁. - (巧妙的利用原子操作和实现无锁编程) 2. 借助原子操作可以实现互斥锁(mutex). (linux中的mutex_lock_t) 3. 借助互斥锁, 可以实现让更多的操作变成原子操作. 三. 单核CPU的原子操作: 在单核CPU中, 能够在一个指令中完成的操作都可以看作为原子操作, 因为中断只发生在指令间. 四. 多核CPU的原子操作: 在多核CPU的时代(确实moore定律有些过时了,我们需要更多的CPU,而不是更快的CPU,无法处理快速CPU中的热量散发问题), 体系中运行着多个独立的CPU, 即使是可以在单个指令中完成的操作也可能会被干扰. 典型的例子就是decl指令(递减指令), 它细分为三个过程: "读->改->写", 涉及两次内存操作. 如果多个CPU运行的多个进程在同时对同一块内存执行这个指令, 那情况是无法预测的. 五. 硬件支持 & 多核原子操作: 软件级别的原子操作是依赖于硬件支持的. 在x86体系中, CPU提供了HLOCK pin引线,

原子操作

天涯浪子 提交于 2019-12-29 02:35:14
   "原子操作(atomic operation)是不需要synchronized",这是Java多线程编程的老生常谈了。   所谓原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch (cpu上下文切换)。   定义:一个操作是原子的(atomic),如果这个操作所处的层(layer)的更高层不能发现其内部实现与结构。原子操作可以是一个步骤,也可以是多个操作步骤,但是其顺序是不可以被打乱,或者切割掉只执行部分。视作整体式原子性的核心。   首先处理器会自动保证基本的内存操作的原子性。处理器保证从系统内存当中读取或者写入一个字节是原子的,意思是当一个处理器读取一个字节时,其他处理器不能访问这个字节的内存地址,也就是lock住这块内存,在我关于信号量的随笔中有提到《windows核心编程》,JVM同样也是。   我们以decl (递减指令)为例,这是一个典型的"读-改-写"过程,涉及两次内存访问。设想在不同CPU运行的两个进程都在递减某个计数值,可能发生的情况是:   ⒈ CPU A(CPU A上所运行的进程,以下同)从内存单元把当前计数值⑵装载进它的寄存器中;   ⒉ CPU B从内存单元把当前计数值⑵装载进它的寄存器中。   ⒊ CPU A在它的寄存器中将计数值递减为1;   ⒋ CPU

全面了解 Java 原子变量类

Deadly 提交于 2019-12-27 18:33:05
【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>> 📦 本文以及示例源码已归档在 javacore 一、原子变量类简介 为何需要原子变量类 保证线程安全是 Java 并发编程必须要解决的重要问题。Java 从原子性、可见性、有序性这三大特性入手,确保多线程的数据一致性。 确保线程安全最常见的做法是利用锁机制( Lock 、 sychronized )来对共享数据做互斥同步,这样在同一个时刻,只有一个线程可以执行某个方法或者某个代码块,那么操作必然是原子性的,线程安全的。互斥同步最主要的问题是线程阻塞和唤醒所带来的性能问题。 volatile 是轻量级的锁(自然比普通锁性能要好),它保证了共享变量在多线程中的可见性,但无法保证原子性。所以,它只能在一些特定场景下使用。 为了兼顾原子性以及锁带来的性能问题,Java 引入了 CAS (主要体现在 Unsafe 类)来实现非阻塞同步(也叫乐观锁)。并基于 CAS ,提供了一套原子工具类。 原子变量类的作用 原子变量类 比锁的粒度更细,更轻量级 ,并且对于在多处理器系统上实现高性能的并发代码来说是非常关键的。原子变量将发生竞争的范围缩小到单个变量上。 原子变量类相当于一种泛化的 volatile 变量,能够 支持原子的、有条件的读/改/写操 作。 原子类在内部使用 CAS 指令(基于硬件的支持)来实现同步