作者:毕来生

微信:878799579

  1. 什么是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

  1. Volatile的优点

可见性:被Volatile修饰的变量可以马上刷新主内存中的值,保证其他线程在获取时可以获取最新值,所有线程看到该变量的值均相同。

轻量级的synchronized,高并发下保证变量的可见性。


6.Volatile的缺点

1、频繁刷新主内存中变量,可能会造成性能瓶颈

2、不具备操作的原子性,不适合在对该变量的写操作依赖于变量本身自己。例如i++,并不能通过volatile来保证原子性

【JUC系列第一篇】-Volatile关键字及内存可见性的更多相关文章

  1. volatile关键字与内存可见性

    前言 首先,我们使用多线程的目的在于提高程序的效率,但是如果使用不当,不仅不能提高效率,反而会使程序的性能更低,因为多线程涉及到线程之间的调度.CPU上下文的切换以及包括线程的创建.销毁和同步等等,开 ...

  2. volatile关键字与内存可见性&原子变量与CAS算法

    1 .volatile 关键字:当多个线程进行操作共享数据时, 可以保证内存中的数据可见 2 .原子变量:jdk1.5后java.util.concurrent.atomic 包下提供常用的原子变量 ...

  3. volatile关键字及内存可见性

    先看一段代码: package com.java.juc; public class TestVolatile { public static void main(String[] args) { T ...

  4. 详解volatile 关键字与内存可见性

    先来看一个例子: public class VolatileTest {            public static void main(String[] args) {           T ...

  5. 深入理解javascript函数系列第一篇——函数概述

    × 目录 [1]定义 [2]返回值 [3]调用 前面的话 函数对任何一门语言来说都是一个核心的概念.通过函数可以封装任意多条语句,而且可以在任何地方.任何时候调用执行.在javascript里,函数即 ...

  6. 【Java并发编程】6、volatile关键字解析&内存模型&并发编程中三概念

    volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在Java 5之后,volatile关键字才得以 ...

  7. 深入理解javascript函数系列第一篇

    前面的话 函数对任何一门语言来说都是核心的概念.通过函数可以封装任意多条语句,而且可以在任何地方.任何时候调用执行.在javascript里,函数即对象,程序可以随意操控它们.函数可以嵌套在其他函数中 ...

  8. volatile关键字解析&内存模型&并发编程中三概念

    原文链接: http://www.cnblogs.com/dolphin0520/p/3920373.html volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java5之前,它是一个 ...

  9. 深入学习jQuery选择器系列第一篇——基础选择器和层级选择器

    × 目录 [1]id选择器 [2]元素选择器 [3]类选择器[4]通配选择器[5]群组选择器[6]后代选择器[7]兄弟选择器 前面的话 选择器是jQuery的根基,在jQuery中,对事件处理.遍历D ...

随机推荐

  1. [转帖]从壹开始前后端分离【重要】║最全的部署方案 & 最丰富的错误分析

    从壹开始前后端分离[重要]║最全的部署方案 & 最丰富的错误分析 https://www.cnblogs.com/laozhang-is-phi/p/beautifulPublish-most ...

  2. QT QcustomPlot的简单使用

    第一步.QcustomPlot是QT提供的一个第三方库,在使用前需要在QcustomPlot官网上进行下载. 第二步.把解压完的QcustomPlot压缩包中的qcustomplot.h和qcusto ...

  3. 前端通过js获取手机型号

    ###前段通过js获取手机型号 需求: 用户登录后记录当前的手机型号并记录 插件: mobile-detect.js插件地址 mobile-device-js插件地址 使用步骤: 获取UA信息-> ...

  4. Python习题004

    作业一:三迁举办选“帅气男孩”,评委打分可以输入打分,要求分数必须大于5,小于10: 方法一 i = 1 while i < 6: score = input("请%d评委打分:&qu ...

  5. (一)第一个python语句、乘除法、获取用户输入、函数

    一.print语句 >>> print "hello World!!" python2 和python3 的print是不一样的,python3的print(“h ...

  6. 本地虚拟机NAT模式下怎么设置才可以访问外网

    记:因为我要在本机虚拟机上安装Docker,结果发现虚拟机环境不能上网,是主机模式.我要调成net模式下才可以访问外网,这就需要怎么设置.下面文章记录一下. 在本机安装VMware软件后,系统中会自动 ...

  7. node 和 postgres

    安装 npm i pg ,如果慢的话,记得爬梯子 连接池的方式: var pg = require('pg'); // 数据库配置 var config = { user:"postgres ...

  8. Java Web 深入分析(1)B/S架构概述

    B/S结构即浏览器和服务器结构.它是随着Internet技术的兴起,对C/S结构的一种变化或者改进的结构.在这种结构下,用户工作界面是通过WWW浏览器来实现,极少部分事务逻辑在前端(Browser)实 ...

  9. javascript的装载和执行

    前言 为什么要采用js来create一个script标签,设置src然后append到head中,而不是直接使用script标签,这样不是更简单点吗? javascript的装载和执行 首先,我想说一 ...

  10. docker系列之六容器数据卷

    docker之容器数据卷 一.容器数据卷 docker容器运行的时候,会产生一系列的文件,那么我们希望容器产生的数据能提供给其他的容器使用,也就是说怎么实现容器间的数据的共享呢?这就需要用到我们所提到 ...