【JUC系列第一篇】-Volatile关键字及内存可见性
作者:毕来生
微信:878799579
- 什么是JUC?
JUC全称 java.util.concurrent 是在并发编程中很常用的实用工具类
2.Volatile关键字
1、如果一个变量被volatile关键字修饰,那么这个变量对所有线程都是可见的。
2、如果某条线程修改了被Volatile修饰的这个变量值,修改后的值对于其他线程来时是立即可见的。
3、并不是经过Volatile修饰过的变量在多线程下就是安全的
4、多线程间可以使用SynchronousQueue或者Exchanger进行数据之间传递
3.内存可见性
内存可见性(Memory Visibility)是指当某个线程正在使用对象状态 而另一个线程在同时修改该状态,需要确保当一个线程修改了对象 状态后,其他线程能够看到发生的状态变化。
可见性错误是指当读操作与写操作在不同的线程中执行时,我们无法确保执行读操作的线程能适时地看到其他线程写入的值,有时甚至是根本不可能的事情。
原理同CAS原理相同,不懂的同学可以自行百度,附上一张CAS演示图供大家参考
4.实战举例
通过线程来修改变量count的值,使用Volatile关键字修饰和不使用Volatile修饰count变量结果对比。
首先我们来看一下通过内部类实现Runnable,变量使用Volatile关键字修饰演示以及结果
package org.bilaisheng.juc;
/**
* @Author: bilaisheng
* @Wechat: 878799579
* @Date: 2019/1/1 16:29
* @Todo: 通过内部类实现Runnable,变量使用Volatile关键字修饰演示
* @Version : JDK11 , IDEA2018
*/
public class NoVolatileTest{
public static void main(String[] args) {
NoVolatileThread noVolatileThread = new NoVolatileThread();
new Thread(noVolatileThread).start();
while (true){
if(noVolatileThread.isFlag()){
System.out.println("flag 此时为true !");
break;
}
}
}
}
class NoVolatileThread implements Runnable{
private boolean flag = false;
@Override
public void run() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
flag = true;
System.out.println(Thread.currentThread().getName() + " flag = " + flag);
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
运行结果如下图所示:
接下来我们来看一下通过内部类实现Runnable,变量不使用Volatile关键字修饰演示以及结果
package org.bilaisheng.juc;
/**
* @Author: bilaisheng
* @Wechat: 878799579
* @Date: 2019/1/1 16:53
* @Todo: 通过内部类实现Runnable,变量使用Volatile关键字修饰演示
* @Version : JDK11 , IDEA2018
*/
public class VolatileTest{
public static void main(String[] args) {
VolatileThread volatileThread = new VolatileThread();
new Thread(volatileThread).start();
while (true){
// if的判断volatile保证当时确实正确,然后线程a可能处于休眠状态,
// 线程b也判断不存在,b线程就new了一个。
// 然后a线程wake up,据需执行new volatile获取最新值。
if(volatileThread.isFlag()){
System.out.println("flag 此时为true !");
break;
}
}
}
}
class VolatileThread implements Runnable{
private volatile boolean flag = false;
@Override
public void run() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
flag = true;
System.out.println(Thread.currentThread().getName() + " flag = " + flag);
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
运行结果如下图所示:
通过对比我们发现在通过Volatile修饰和不通过Volatile修饰的变量,输出结果竟然会有些偏差。到底是为什么呢?
我们逐步拆解上面代码执行步骤:
1、针对于不使用Volatile关键字修饰变量:
- 步骤一:默认flag = false;
- 步骤二main线程的缓存区域没有刷新 flag的值。所以flag 还是false。故没有输出<flag 此时为true !>
- 步骤三:子线程输出 Thread-0 flag = true
2、针对于使用Volatile关键字修饰变量:
- 步骤一:默认flag = false;
- 步骤二:主线程看到flag是被Volatile关键字修饰的变量。则获取最新的flag变量值,此时flag = true。故输出<flag 此时为true !>
- 步骤三:子线程输出 Thread-0 flag = true
- Volatile的优点
可见性:被Volatile修饰的变量可以马上刷新主内存中的值,保证其他线程在获取时可以获取最新值,所有线程看到该变量的值均相同。
轻量级的synchronized,高并发下保证变量的可见性。
6.Volatile的缺点
1、频繁刷新主内存中变量,可能会造成性能瓶颈
2、不具备操作的原子性,不适合在对该变量的写操作依赖于变量本身自己。例如i++,并不能通过volatile来保证原子性
【JUC系列第一篇】-Volatile关键字及内存可见性的更多相关文章
- volatile关键字与内存可见性
前言 首先,我们使用多线程的目的在于提高程序的效率,但是如果使用不当,不仅不能提高效率,反而会使程序的性能更低,因为多线程涉及到线程之间的调度.CPU上下文的切换以及包括线程的创建.销毁和同步等等,开 ...
- volatile关键字与内存可见性&原子变量与CAS算法
1 .volatile 关键字:当多个线程进行操作共享数据时, 可以保证内存中的数据可见 2 .原子变量:jdk1.5后java.util.concurrent.atomic 包下提供常用的原子变量 ...
- volatile关键字及内存可见性
先看一段代码: package com.java.juc; public class TestVolatile { public static void main(String[] args) { T ...
- 详解volatile 关键字与内存可见性
先来看一个例子: public class VolatileTest { public static void main(String[] args) { T ...
- 深入理解javascript函数系列第一篇——函数概述
× 目录 [1]定义 [2]返回值 [3]调用 前面的话 函数对任何一门语言来说都是一个核心的概念.通过函数可以封装任意多条语句,而且可以在任何地方.任何时候调用执行.在javascript里,函数即 ...
- 【Java并发编程】6、volatile关键字解析&内存模型&并发编程中三概念
volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在Java 5之后,volatile关键字才得以 ...
- 深入理解javascript函数系列第一篇
前面的话 函数对任何一门语言来说都是核心的概念.通过函数可以封装任意多条语句,而且可以在任何地方.任何时候调用执行.在javascript里,函数即对象,程序可以随意操控它们.函数可以嵌套在其他函数中 ...
- volatile关键字解析&内存模型&并发编程中三概念
原文链接: http://www.cnblogs.com/dolphin0520/p/3920373.html volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java5之前,它是一个 ...
- 深入学习jQuery选择器系列第一篇——基础选择器和层级选择器
× 目录 [1]id选择器 [2]元素选择器 [3]类选择器[4]通配选择器[5]群组选择器[6]后代选择器[7]兄弟选择器 前面的话 选择器是jQuery的根基,在jQuery中,对事件处理.遍历D ...
随机推荐
- [转帖]从壹开始前后端分离【重要】║最全的部署方案 & 最丰富的错误分析
从壹开始前后端分离[重要]║最全的部署方案 & 最丰富的错误分析 https://www.cnblogs.com/laozhang-is-phi/p/beautifulPublish-most ...
- QT QcustomPlot的简单使用
第一步.QcustomPlot是QT提供的一个第三方库,在使用前需要在QcustomPlot官网上进行下载. 第二步.把解压完的QcustomPlot压缩包中的qcustomplot.h和qcusto ...
- 前端通过js获取手机型号
###前段通过js获取手机型号 需求: 用户登录后记录当前的手机型号并记录 插件: mobile-detect.js插件地址 mobile-device-js插件地址 使用步骤: 获取UA信息-> ...
- Python习题004
作业一:三迁举办选“帅气男孩”,评委打分可以输入打分,要求分数必须大于5,小于10: 方法一 i = 1 while i < 6: score = input("请%d评委打分:&qu ...
- (一)第一个python语句、乘除法、获取用户输入、函数
一.print语句 >>> print "hello World!!" python2 和python3 的print是不一样的,python3的print(“h ...
- 本地虚拟机NAT模式下怎么设置才可以访问外网
记:因为我要在本机虚拟机上安装Docker,结果发现虚拟机环境不能上网,是主机模式.我要调成net模式下才可以访问外网,这就需要怎么设置.下面文章记录一下. 在本机安装VMware软件后,系统中会自动 ...
- node 和 postgres
安装 npm i pg ,如果慢的话,记得爬梯子 连接池的方式: var pg = require('pg'); // 数据库配置 var config = { user:"postgres ...
- Java Web 深入分析(1)B/S架构概述
B/S结构即浏览器和服务器结构.它是随着Internet技术的兴起,对C/S结构的一种变化或者改进的结构.在这种结构下,用户工作界面是通过WWW浏览器来实现,极少部分事务逻辑在前端(Browser)实 ...
- javascript的装载和执行
前言 为什么要采用js来create一个script标签,设置src然后append到head中,而不是直接使用script标签,这样不是更简单点吗? javascript的装载和执行 首先,我想说一 ...
- docker系列之六容器数据卷
docker之容器数据卷 一.容器数据卷 docker容器运行的时候,会产生一系列的文件,那么我们希望容器产生的数据能提供给其他的容器使用,也就是说怎么实现容器间的数据的共享呢?这就需要用到我们所提到 ...