volatile

ConcurrentHashMap源码解析(1.8)

末鹿安然 提交于 2020-03-20 07:58:47
一、简介 上篇文章 详细介绍了HashMap的源码及原理,本文趁热打铁继续分析ConcurrentHashMap的原理。 首先在看本文之前,希望对HashMap有一个详细的了解。不然看直接看ConcurrentHashMap的源码还是有些费劲的。 相信对HashMap,HashTable有一定了解,应该知道HashMap是不具备线程安全性的,在resize时会丢数据(JDK8),而HashTable虽然保证了线程安全性,但是其是通过给每个方法加Synchronized关键字达到的同步目的。但是都知道Synchronized在竞争激烈的多线程并发环境中,在性能上的表现是非常不如人意的。那在高并发环境中HashMap如何保证线程安全而又不浪费太多性能呢?答案就是Java J.U.C并发包中的ConcurrentHashMap。 依然开局一张图。JDK8中的ConcurrentHashMap数据结构。 呃呵,和HashMap的结构是一样的,没错在数据结构层面,ConcurrentHashMap和HashMap是完全一样的。有了这个基础继续往下看。 二、历史版本 ConcurrentHashMap的历史版本大致分界线在JDK8。也就是可以分为JDK8和JDK8以前版本。 数据结构的区别 在JDK8之前HashMap没有引入红黑树,同样的ConcurrentHashMap也没有引入红黑树

Is processor cache flushed during context switch in multicore?

倾然丶 夕夏残阳落幕 提交于 2020-03-18 17:38:37
问题 Recently, I discussed why there is a volatile mark at seq in Java Actors demo @volatile private var seq = 0L private def nextSeq: Long = { val next = seq seq += 1 next } One answer was that threads can be migrated and variables lost (other cores will have incoherent values in their private caches). But, you not normally mark every variable with volatile to enable multicore execution. So, cores must flush the caches whenever context is switched. But, I cannot find this statement pronounced

因为我说:volatile 是轻量级的 synchronized,面试官让我回去等通知!

倾然丶 夕夏残阳落幕 提交于 2020-03-18 13:27:45
volatile 是并发编程的重要组成部分,也是面试常被问到的问题之一。不要向小强那样,因为一句:volatile 是轻量级的 synchronized,而与期望已久的大厂失之交臂。 volatile 有两大特性:保证内存的可见性和禁止指令重排序。那什么是可见性和指令重排呢?接下来我们一起来看。 内存可见性 要了解内存可见性先要从 Java 内存模型(JMM)说起,在 Java 中所有的共享变量都在主内存中,每个线程都有自己的工作内存,为了提高线程的运行速度,每个线程的工作内存都会把主内存中的共享变量拷贝一份进行缓存,以此来提高运行效率,内存布局如下图所示: 但这样就会产生一个新的问题,如果某个线程修改了共享变量的值,其他线程不知道此值被修改了,就会发生两个线程值不一致的情况,我们用代码来演示一下这个问题。 public class VolatileExample { // 可见性参数 private static boolean flag = false; public static void main(String[] args) { new Thread(() -> { try { // 暂停 0.5s 执行 Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } flag =

(十二)J.U.C之atomic框架:AtomicInteger

℡╲_俬逩灬. 提交于 2020-03-17 11:55:12
一、简介 AtomicInteger类,应该是atomic框架中用得最多的原子类了。顾名思义,AtimicInteger是Integer原型的线程安全原子类,可以在应用程序中以原子的方式更新int值。 1.创建 AtomicInteger提供了两个构造器,使用默认构造器时,内部int类型的value值为0: AtomicInteger atomicInt = new AtomicInteger(); AtomicInteger类的内部并不复杂,所有的操作都针对内部的int值——value,并通过unsafe类来实现线程安全的CAS操作: 2.AtomicInteger的使用 public class Main { public static void main(String[] args) throws InterruptedException { AtomicInteger ai = new AtomicInteger(); List<Thread> list = new ArrayList<>(); for (int i = 0; i < 10; i++) { Thread t = new Thread(new Accumlator(ai), "thread-" + i); list.add(t); t.start(); } for (Thread t : list) { t

Java Grammar(三):修饰符

风格不统一 提交于 2020-03-17 09:21:36
简介 修饰符是用于限定类型以及类型成员申明的一种符号,从修饰对象上可以分为类修饰符,方法修饰符,变量修饰符;从功能上可以划分为访问控制修饰符和非访问修饰符。访问修饰符控制访问权限,不同的访问修饰符有不同的权限范围,而非访问修饰符则是提供一些特有功能。 下面我们从功能的角度分别讲解修饰符 访问修饰符 访问修饰符有四种: public , private , protected , default 。这里需要注意,我们这里的 default 和非访问修饰符中的 default 可不是一个东西! 这里的 default 指的是默认, 什么也不写 ,在同一包内可见,不使用任何修饰符。使用对象: 类、接口、变量、方法 。 private 指的是在仅仅在类内可见,所以也就很好理解, private 只能修饰 方法,变量 ,而不能修饰类和接口(毕竟你只能类内访问,你修饰类谁能看得到呢?),修饰方法的时候,一般用于我们在重构代码的时候提取公用代码为 内部实现方法 ,修饰变量的情景相比我们就经常见到了,由于Java的 封装 特性,我们在定义一个类的时候,经常会把该类的属性定义为 private ,通过 get or set 方法来访问这些变量。 而 public 在我们日常中使用的比较多,我们经常会把类声明为 public ,声明成 public 的 类,接口,变量,方法 可以被任何类访问

Java内存模型

非 Y 不嫁゛ 提交于 2020-03-17 08:59:43
Java内存模型 原本准备把内存模型单独放到某一篇文章的某个章节里面讲解,后来查阅了国外很多文 档才发现其实JVM内存模型的内容还蛮多的,所以直接作为一个章节的基础知识来讲解,可能该章节概念的东西比较多。一个开发Java的开发者,一旦了解了 JVM内存模型就能够更加深入地了解该语言的语言特性,可能这个章节更多的是概念,没有太多代码实例,所以希望读者谅解,有什么笔误来Email告知: silentbalanceyh@126.com , 本文尽量涵盖所有Java语言可以碰到的和内存相关的内容,同样也会提到一些和内存相关的计算机语言的一些知识,为草案。因为平时开发的时候没有特殊情况 不会进行内存管理,所以有可能有笔误的地方比较多,我用的是Windows平台,所以本文涉及到的与操作系统相关的只是仅仅局限于Windows平台。不 仅仅如此,这一个章节牵涉到的多线程和另外一些内容并没有讲到,这里主要是结合JVM内部特性把本章节作为核心的概念性章节来讲解,这样方便初学者深入以 及彻底理解Java语言) 本文章节: 1.JMM简介 2.堆和栈 3.本机内存 4.防止内存泄漏 1.JMM简介    i.内存模型概述   Java平台自动集成了 线程 以及 多处理器技术 ,这种集成程度比Java以前诞生的计算机语言要厉害很多,该语言针对 多种异构平台的平台独立性

走进 Java Volatile 关键字

核能气质少年 提交于 2020-03-17 07:50:43
Java Volatile 关键字是一种轻量级的数据一致性保障机制,之所以说是轻量级的是因为 volatile 不具备原子性,它对数据一致性的保障体现在对修改过的数据进行读取的场景下(也就是数据的可见性)。比起对读操作使用互斥锁, volatile 是一种很高效的方式。因为 volatile 不会涉及到线程的上下文切换,以及操作系统对线程执行的调度运算。同时 volidate 关键字的另一个功能是解决“指令重排序问题”。 Volatile 可见性承诺 Java volatile关键字保证了跨线程更改线程间共享变量的可见性。这可能听起来有点抽象,让我们详细说明一下。 在多线程应用程序中,线程对 non-volatile 变量进行操作,出于性能原因,每个线程在处理变量时,可以将它们从主内存复制到CPU缓存中。如果你的计算机包含一个以上的CPU,每个线程可以在不同的CPU上运行。这意味着,每个线程可以将同一个变量复制到不同CPU的CPU缓存中。这就和计算机的组成和工作原理息息相关了,之所以在每一个 CPU 中都含有缓存模块是因为出于性能考虑。因为 CPU 的执行速度要比内存(这里的内存指的是 Main Memory)快很多,因为 CPU 要对数据进行读、写的操作,如果每次都和内存进行交互那么 CPU 在等待 I/O 这个过程中就消耗了大量时间

关于Java变量的可见性问题

你离开我真会死。 提交于 2020-03-16 11:54:15
某厂面试归来,发现自己落伍了!>>> 关于Java变量的可见性问题 博文前提 最近在oschina问答板块看到了一个关于java变量在工作内存和主存中的可见性问题: synchorized,sleep 也能达到volatile 线程可见性的目的? ,大致的问题描述如下: package com.test; import java.util.concurrent.TimeUnit; public class test1 { private static boolean is = true; public static void main(String[] args) { new Thread(new Runnable() { @Override public void run() { int i = 0; while(test1.is){ i++; 1 //synchronized (this) { } 会强制刷新主内存的变量值到线程栈? 2 //System.out.println("1"); println 是synchronized 的,会强制刷新主内存的变量值到线程栈? 3 //sleep 会从新load主内存的值? // try { // TimeUnit.MICROSECONDS.sleep(1); // }catch (InterruptedException e) {

为什么volatile能保证可见性?

不打扰是莪最后的温柔 提交于 2020-03-16 11:36:45
某厂面试归来,发现自己落伍了!>>> 我们都知道volatile能保证可见性,不能保证原子性,比如i++操作 也知道Happen-Before原则,那么是如何确保Happen-Before原则不被指令重排序影响呢?(如果对上述描述有困惑请移步 [高并发Java 三] Java内存模型和线程安全 ) 例如你让一个volatile的integer自增(i++),其实要分成3步:1)读取volatile变量值到local; 2)增加变量的值;3)把local的值写回,让其它的线程可见。这3步的jvm指令为: mov 0xc(%r10),%r8d ; Load inc %r8d ; Increment mov %r8d,0xc(%r10) ; Store lock addl $0x0,(%rsp) ; StoreLoad Barrier StoreLoad Barrier就是内存屏障 内存屏障( memory barrier )是一个CPU指令。基本上,它是这样一条指令: a) 确保一些特定操作执行的顺序; b) 影响一些数据的可见性(可能是某些指令执行后的结果)。编译器和CPU可以在保证输出结果一样的情况下对指令重排序,使性能得到优化。插入一个内存屏障,相当于告诉CPU和编译器先于这个命令的必须先执行,后于这个命令的必须后执行。内存屏障另一个作用是强制更新一次不同CPU的缓存。例如

Java 修饰符

生来就可爱ヽ(ⅴ<●) 提交于 2020-03-16 03:20:55
访问修饰符 Java中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。Java支持4种不同的访问权限。 默认的,也称为default,在同一包内可见,不使用任何修饰符。 私有的,以private修饰符指定,在同一类内可见。 共有的,以public修饰符指定,对所有类可见。 受保护的,以protected修饰符指定,对同一包内的类和所有子类可见。 非访问修饰符 static修饰符 静态变量: static关键字用来声明独立于对象的静态变量,无论一个类实例化多少对象,它的静态变量只有一份拷贝。静态变量也被称为类变量。局部变量不能被声明为static变量。 静态方法: static关键字用来声明独立于对象的静态方法。静态方法不能使用类的非静态变量。静态方法从参数列表得到数据,然后计算这些数据。 fianl修饰符 final变量: final变量能被显式地初始化并且只能初始化一次。被声明为final的对象的引用不能指向不同的对象。但是final对象里的数据可以被改变。也就是说final对象的引用不能改变,但是里面的值可以改变。 final修饰符通常和static修饰符一起使用来创建类常量。 final方法: 类中的Final方法可以被子类继承,但是不能被子类修改。 final类: final类不能被继承 abstract修饰符 抽象类: 抽象类不能用来实例化对象