作者:毕来生

微信: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. [数据结构] - ArrayList探究

    一 概述 ArrayList可以理解为动态数组,与java的数组相比,它的容量能动态曾长,ArrayList是List接口的可变数组的实现,允许包括null值在内的所有元素.除了实现List接口外,此 ...

  2. day0~day13

    day0 day1 day2 day4 day5 day7 day9 day10 day12 day13

  3. XDebug调试

    安装 访问Xdebug 点击download 找到RELEASES,点击 custom installation instructions. 在白色框框内填入phpinfo()出来的源码 点击Anal ...

  4. python学习-46 时间模块

    时间模块 ····时间戳 print(time.time()) 运行结果: 1564294158.0389376 Process finished with exit code 0 ·····结构化时 ...

  5. 纯css实现移动端横向滑动列表&&overflow:atuo;隐藏滚动条

    <!DOCTYPE html> <html> <head> <title>横向滑动</title> <style type=" ...

  6. 关于财务YT知识点

    1 YT 将今年剩余的未花完的money做YT,生成一个YT号,用在下一年使用的机制. 2 生成YT的方式 2.1 PR生成YT 2.2 PO生成YT 2.3 TR生成YT 2.4 预算直接生成YT ...

  7. C#projectPropertyGrid 显示结构(展开逗号分隔)

    [TypeConverter(typeof(ExpandableObjectConverter))] public A MyA { get{..} set{..} }

  8. Go part 5 结构体,方法与接收器

    结构体 结构体定义 结构体的定义只是一种内存布局的描述(相当于是一个模板),只有当结构体实例化时,才会真正分配内存空间 结构体是一种复合的基本类型,通过关键字 type 定义为 自定义 类型后,使结构 ...

  9. xcode 更改svn地址

    xcode如何更改svn地址: 1在控制台 cd进入到项目路径下 命令提示符下输入 $svn info 查看svn信息 修改svn地址 输入如下命令 $svn switch --relocate ht ...

  10. 私服nexus的权限问题,带admin和带view的区别

    admin和view的区别只找到了这个解释: https://blog.csdn.net/tian_111222333/article/details/100159983 最终得出答案,我只需要给他们 ...