背景:听说Volatile Java高阶语法亦是挺进BAT的必经之路。

Volatile

volatile同步机制又涉及Java内存模型中的可见性、原子性和有序性,恶补基础一波。

可见性:

可见性简单的说是线程之间的可见性,一个线程修改的状态对另一个线程是可见对,也就是一个线程的修改结果另一个线程可以马上看到;但通常,我们无法确保执行读操作的线程能够时时的看到其他线程写入的值,So为了确保多个线程之间对内存写入操作可见性,必须使用同步机制;如用volatile修饰的变量就具有可见性,volatile修饰的变量不允许线程内部缓存和重排序,而是直接修改内存,所以对其他线程来说是可见的;但volatile只能保证被修饰的内容具有可见性,并不具备原子性,如volatile int vipNumber = 100,之后有一个vipNumber++ 的操作,这个变量vipNumber具有可见性,但是vipNumber++ 依然是一个非原子操作,也就是说这个操作同样存在线程安全问题。

原子性:

原子具有不可分割的特性,如int age = 22,这个操作是不可分割的,那么称其为原子操作,具有原子性;再比如age++,这个操作实际是age = age + 1,其是可分割的,So它不是一个原子操作;而非原子操作都会存在线程安全问题,需要我们使用同步技术(synchronized)来让它变成一个原子操作;Java的concurrent包下提供了一些原子类,如:AtomicLongMap、AtomicDouble、AtomicReference 等;在Java中用synchronized、lock和unlock来保证原子性。

有序性:

Java语言提供了volatile和synchronized两个关键字来保证线程之间操作的有序性,volatile是因为本身包含“禁止指令重排序”的语义,synchronized是由“一个变量在同一时刻只允许一条线程对其进行lock操作”这条规则获得有序性的,此规则决定了持有同一个对象锁的两个同步块只能串行执行。

Volatile原理:

volatile是一种稍弱的同步机制,其用来确保将变量的更新操作通知到其他线程;当变量声明为volatile类型后,编译器与JVM运行时都会注意到这个变量时共享的,因此不会将此变量上的操作与其他操作一起重排序;volatile修饰后变量不会缓存在寄存器或者对其他处理器不可见的地方,因此在单曲volatile类型的变量时总会返回最新写入的值;除此之外,在访问volatile变量时不会执行加锁操作,也就不会执行线程阻塞,因此volatile变量是一种比synchronized关键字更轻量级的同步机制;当对非volatile变量进行读写时,每个线程从内存拷贝变量到CPU缓存中,如果计算机有多个CPU则每个线程可能在不同的CPU上被处理,这就意味着每个线程都可以拷贝到不同的CPU缓存cache中,而不是像volatile变量那样直接读内存,JVM保证其每次读变量都从内存中读,跳过了CPU cache这一步骤。

当一个变量定义为volatile之后,其具备的两种特征:

1、保证此变量对所有的线程的可见性;当一个线程修改了此变量的值,volatle保证新值能够立即同步到主内存,以及每次使用前立即从主每次刷新;

2、禁止指令重排序优化;被volatile修饰的变量赋值后多执行了一个“load”操作,此操作相当于一个内存屏障(指令重排序时不能把后面的指令重排序到内存屏障之前到位置),只有一个CPU访问内存时,不需要内存屏障;(指令重排序:指CPU采用了允许将多条指令不按程序规定的顺序分开发送给各相应电路单元处理)

另外:在性能方面,volatile的读操作性能消耗与普通变量基本无异,但是写操作稍慢,因为它需要在本地代码中插入许多内存屏障来保证处理器不发生乱序执行。

这里撸了一个例子用volatile保证线程间的同步,如果变量author不经volatile修饰,线程2中对author的值做了修改并未同步到线程1中,其一直存在缓存中。

FYI:

 import lombok.extern.slf4j.Slf4j;

 @Slf4j
public class TestVolatile {
//private volatile String author = "tjt"; // volatile修饰author保证两个线程到可见性,即不存在缓存cache中
private String author = "tjt"; // 不用volatile修饰变量author则author修改值后在线程之间并不可见
private boolean enable = false;
public static void main(String[] args) throws Exception {
TestVolatile testVolatile = new TestVolatile();
log.info("原始定义的author: "+testVolatile.author);
Thread thread = new Thread( new Runnable() {
@Override
public void run() {
testVolatile.testMethodOne();
}
});
thread.start();
thread.sleep(2000l);
testVolatile.testMethodTwo();
}
public void testMethodOne() {
while(true) {
if ("detect_tjt".equals(author) && enable == false) {
log.info("线程testMethodOne中检测到来author修改为: "+author);
enable = true;
System.exit(0);
}
} }
public void testMethodTwo() {
author = "detect_tjt";
log.info("线程testMethodTwo中把author修改为: "+author);
}
}

用volatile修饰author执行结果:
- 原始定义的author: tjt
- 线程testMethodTwo中把author修改为: detect_tjt
- 线程testMethodOne中检测到来author修改为: detect_tjt
无volatile修饰author执行结果:

- 原始定义的author: tjt
- 线程testMethodTwo中把author修改为: detect_tjt

Java高阶语法---Volatile的更多相关文章

  1. Java高阶语法---transient

    背景:听说transient Java高阶语法是挺进BAT必经之路. transient: Java中transient 关键字的作用,简单的说就是让某些被修饰的成员属性变量不被序列化. 这又扯到了序 ...

  2. Java高阶语法---static

    背景:听说static Java高阶语法是挺进BAT必经之路. static: 静态static,很多时候会令我望文生义,但是get到了static最重要的一点,其他的理解都还ok. static最重 ...

  3. Java高阶语法---final

    背景:听说final Java高阶语法是挺进BAT必经之路. final: final关键字顾名思义就是最终不可改变的. 1.含义:final可以声明成员变量.方法.类和本地变量:一旦将引用声明为fi ...

  4. Cmd Markdown 高阶语法手册

    『Cmd 技术渲染的沙箱页面,点击此处编写自己的文档』 Cmd Markdown 高阶语法手册 1. 内容目录 在段落中填写 [TOC] 以显示全文内容的目录结构. [TOC] 2. 标签分类 在编辑 ...

  5. Markdown 高阶语法

    记录一些 Markdown 的高阶语法,想起来什么,再更新 分割线 两条分割线 *** *** 插入表格 Column Column Column Row Content Content | Colu ...

  6. Java高并发同步Volatile的使用

    引言: 在多线程并发编程中synchronized和Volatile都扮演着重要的角色,Volatile是轻量级的synchronized,它在多处理器开发中保证了共享变量的“可见性”. 可见性的意思 ...

  7. Java高阶面试问题合集

    下面总结一下在Java面试中常用的一些问题,不具体解答,我只附上一些精彩的博文链接. Spring IOC AOP 底层原理 JAVA的反射机制和动态代理 Java反射机制和动态代理 多线程 Spri ...

  8. Java高阶回调,回调函数的另一种玩法

    工具类package com.sctek; import java.lang.reflect.Field; import android.os.CountDownTimer;import androi ...

  9. MySQL-5.7 高阶语法及流程控制

    1.标签语句 [begin_label:] BEGIN [statement_list] END [end_label] [begin_label:] LOOP statement_list END ...

随机推荐

  1. LeetCode笔记:39. Combination Sum

    题目描述 给定一个无重复的正整数数组 candidates 和一个正整数 target, 求所有和为 target 的 candidates 中数的组合中.其中相同数的不同顺序组合算做同一种组合,ca ...

  2. [微信小程序]编译.wxss出错,2 not found

    小程序新建项目就出错:2 not found  编译.wxss文件出错(不是一般的郁闷,新建项目就报错...) 大概的情况是开发工具没有更新.或更新不到, 第一,可以删掉开发工具重新下载最新安装: 第 ...

  3. Unity进阶----AssetBundle_03(2018/11/07)

    1. 为啥有AB包? 因为资源需要更新, 避免更新一次打包一次 动态修改. 2. AB包注意啥? 依赖关系 找依赖关系应该找到对应的平台!!! 3. 打包策略是分场景打包 若文件被文件夹包含打包出来的 ...

  4. es5中的for in 与es6中的for of的用法与区别

    for in 用与循环遍历对象中的属性键值 for of用于循环遍历出数组中的属性值 for in 也可以遍历数组,但是局限是他会把数组的其他属性键值也会遍历出,例如给数组添加一个属性arr.name ...

  5. tag cloud的相关资料

    http://reverland.org/python/2013/01/28/visualize-your-shell-history/ https://github.com/reverland/sc ...

  6. java内存分页计算

    介绍三个最常用的分页算法 First(感觉这个最简单实用) //总记录数int rows=21; //每页显示的记录数int pageSize=5; //页数int pageSum=(rows-1)/ ...

  7. freekan5.9电影网站安装及源码分享

    Freekan是一套目前非常火的电影网站系统,全自动采集,支持对接公众号 服务器环境:centos7,宝塔面板,php7.1(重要),nignx,mysql 1.首先上传压缩包到网站目录,然后解压 2 ...

  8. LeetCode题解41.First Missing Positive

    41. First Missing Positive Given an unsorted integer array, find the first missing positive integer. ...

  9. JS中的特殊类别注意区分

    undefined和null 在JavaScript中存在这样两种原始类型:Null与Undefined. 这两种类型常常会使JavaScript的开发人员产生疑惑,在什么时候是Null,什么时候又是 ...

  10. 【从零开始搭建自己的.NET Core Api框架】(一)创建项目并集成swagger:1.1 创建

    系列目录 一.  创建项目并集成swagger 1.1 创建 1.2 完善 二. 搭建项目整体架构 三. 集成轻量级ORM框架——SqlSugar 3.1 搭建环境 3.2 实战篇:利用SqlSuga ...