背景:据说Volatile Java高阶语法亦是挺进BAT的必经之路。缓存
Volatile:安全
volatile同步机制又涉及Java内存模型中的可见性、原子性和有序性,恶补基础一波。ide
可见性:性能
可见性简单的说是线程之间的可见性,一个线程修改的状态对另外一个线程是可见对,也就是一个线程的修改结果另外一个线程能够立刻看到;但一般,咱们没法确保执行读操做的线程可以时时的看到其余线程写入的值,So为了确保多个线程之间对内存写入操做可见性,必须使用同步机制;如用volatile修饰的变量就具备可见性,volatile修饰的变量不容许线程内部缓存和重排序,而是直接修改内存,因此对其余线程来讲是可见的;但volatile只能保证被修饰的内容具备可见性,并不具有原子性,如volatile int vipNumber = 100,以后有一个vipNumber++ 的操做,这个变量vipNumber具备可见性,可是vipNumber++ 依然是一个非原子操做,也就是说这个操做一样存在线程安全问题。优化
原子性:spa
原子具备不可分割的特性,如int age = 22,这个操做是不可分割的,那么称其为原子操做,具备原子性;再好比age++,这个操做实际是age = age + 1,其是可分割的,So它不是一个原子操做;而非原子操做都会存在线程安全问题,须要咱们使用同步技术(synchronized)来让它变成一个原子操做;Java的concurrent包下提供了一些原子类,如:AtomicLongMap、AtomicDouble、AtomicReference 等;在Java中用synchronized、lock和unlock来保证原子性。线程
有序性:code
Java语言提供了volatile和synchronized两个关键字来保证线程之间操做的有序性,volatile是由于自己包含“禁止指令重排序”的语义,synchronized是由“一个变量在同一时刻只容许一条线程对其进行lock操做”这条规则得到有序性的,此规则决定了持有同一个对象锁的两个同步块只能串行执行。对象
Volatile原理:blog
volatile是一种稍弱的同步机制,其用来确保将变量的更新操做通知到其余线程;当变量声明为volatile类型后,编译器与JVM运行时都会注意到这个变量时共享的,所以不会将此变量上的操做与其余操做一块儿重排序;volatile修饰后变量不会缓存在寄存器或者对其余处理器不可见的地方,所以在单曲volatile类型的变量时总会返回最新写入的值;除此以外,在访问volatile变量时不会执行加锁操做,也就不会执行线程阻塞,所以volatile变量是一种比synchronized关键字更轻量级的同步机制;当对非volatile变量进行读写时,每一个线程从内存拷贝变量到CPU缓存中,若是计算机有多个CPU则每一个线程可能在不一样的CPU上被处理,这就意味着每一个线程均可以拷贝到不一样的CPU缓存cache中,而不是像volatile变量那样直接读内存,JVM保证其每次读变量都从内存中读,跳过了CPU cache这一步骤。
当一个变量定义为volatile以后,其具有的两种特征:
一、保证此变量对全部的线程的可见性;当一个线程修改了此变量的值,volatle保证新值可以当即同步到主内存,以及每次使用前当即从主每次刷新;
二、禁止指令重排序优化;被volatile修饰的变量赋值后多执行了一个“load”操做,此操做至关于一个内存屏障(指令重排序时不能把后面的指令重排序到内存屏障以前到位置),只有一个CPU访问内存时,不须要内存屏障;(指令重排序:指CPU采用了容许将多条指令不按程序规定的顺序分开发送给各相应电路单元处理)
另外:在性能方面,volatile的读操做性能消耗与普通变量基本无异,可是写操做稍慢,由于它须要在本地代码中插入许多内存屏障来保证处理器不发生乱序执行。
这里撸了一个例子用volatile保证线程间的同步,若是变量author不经volatile修饰,线程2中对author的值作了修改并未同步到线程1中,其一直存在缓存中。
FYI:
1 import lombok.extern.slf4j.Slf4j; 2
3 @Slf4j 4 public class TestVolatile { 5 //private volatile String author = "tjt"; // volatile修饰author保证两个线程到可见性,即不存在缓存cache中
6 private String author = "tjt"; // 不用volatile修饰变量author则author修改值后在线程之间并不可见
7 private boolean enable = false; 8 public static void main(String[] args) throws Exception { 9 TestVolatile testVolatile = new TestVolatile(); 10 log.info("原始定义的author: "+testVolatile.author); 11 Thread thread = new Thread( new Runnable() { 12 @Override 13 public void run() { 14 testVolatile.testMethodOne(); 15 } 16 }); 17 thread.start(); 18 thread.sleep(2000l); 19 testVolatile.testMethodTwo(); 20 } 21 public void testMethodOne() { 22 while(true) { 23 if ("detect_tjt".equals(author) && enable == false) { 24 log.info("线程testMethodOne中检测到来author修改成: "+author); 25 enable = true; 26 System.exit(0); 27 } 28 } } 29 public void testMethodTwo() { 30 author = "detect_tjt"; 31 log.info("线程testMethodTwo中把author修改成: "+author); 32 } 33 }
用volatile修饰author执行结果:
- 原始定义的author: tjt
- 线程testMethodTwo中把author修改成: detect_tjt
- 线程testMethodOne中检测到来author修改成: detect_tjt
无volatile修饰author执行结果:
- 原始定义的author: tjt
- 线程testMethodTwo中把author修改成: detect_tjt