volatile原理

    Java语言提供了一种稍弱的同步机制,即volatile变量,用来确保将变量的更新操作通知到其他线程。当把变量声明为volatile类型后,

编译器与运行时都会注意到这个变量是共享的,因此不会将该变量上的操作与其他内存操作一起重排序。volatile变量不会被缓存在寄

存器或者对其他处理器不可见的地方,因此在读取volatile类型的变量时总会返回最新写入的值

     当对非 volatile 变量进行读写的时候,每个线程先从内存拷贝变量到CPU缓存中。如果计算机有多个CPU,每个线程可能在不同的CPU

上被处理,这意味着每个线程可以拷贝到不同的 CPU cache 中。而声明变量是 volatile 的,JVM 保证了每次读变量都从内存中读

    当一个变量定义为 volatile 之后,将具备两种特性:

  1.保证此变量对所有的线程的可见性,这里的“可见性”,指当一个线程修改了这个变量的值,volatile 保证了新值能立即同步到主内存,

以及每次使用前立即从主内存刷新。但普通变量做不到这点,普通变量的值在线程间传递均需要通过主内存来完成,即复制变量值到当前线

程缓存中修改,然后再返回给主内存。

  2.禁止指令重排序优化。什么是指令重排序:是指CPU采用了允许将多条指令不按程序规定的顺序分开发送给各相应电路单元处理。

   并发编程的三个特性

1.原子性

原子性:即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行

2.可见性

可见性是指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值

//线程1执行的代码
int i = 0;
i = 10; //线程2执行的代码
j = i;

当线程1执行 i =10这句时,会先把i的初始值加载到CPU1的高速缓存中,然后赋值为10,那么在CPU1的高速缓存当中i的值变为10了,却没有立即写入到主存当中。

此时线程2执行 j = i,它会先去主存读取i的值并加载到CPU2的缓存当中,注意此时内存当中i的值还是0,那么就会使得j的值为0,而不是10.

这就是可见性问题,线程1对变量i修改了之后,线程2没有立即看到线程1修改的值。

3.有序性

有序性:即程序执行的顺序按照代码的先后顺序执行

int i = 0;
int j = 0;
i = 10; //语句1
j = 1; //语句2

语句可能的执行顺序如下:

  • 1)语句1 语句2
  • 2)语句2 语句1

语句1一定在语句2前面执行吗?答案是否定的,这里可能会发生执行重排(Instruction Reorder)。一般来说,处理器为了提高程序运行效率,

可能会对输入代码进行优化,它不保证程序中各个语句的执行先后顺序同代码中的顺序一致,但是它会保证程序在单线程环境下最终执行结果和

代码顺序执行的结果是一致的。

   volatile实例

1.变量没有使用volatile关键字

package com.thread.volatileintroduce;

/**
* 没有使用Volatile关键字
*
* @author yyx 2019年1月12日
*/
public class NoVolatile {
public static void main(String[] args) {
ThreadDemo td = new ThreadDemo();
new Thread(td).start(); while (true) {
if (td.isFlag()) {
System.out.println("------------------");
break;
}
}
}
} class ThreadDemo implements Runnable {
private boolean flag = false; @Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
flag = true;
System.out.println("flag=" + isFlag());
} public boolean isFlag() {
return flag;
} public void setFlag(boolean flag) {
this.flag = flag;
}
}
运行结果:flag=true

主线程不会打印出“--------------”

2.使用volatile关键字

package com.thread.volatileintroduce;

/**
* 使用Volatile关键字
* volatile 关键字:当多个线程进行操作共享数据时,可以保证内存中的数据可见。 相较于 synchronized
* 是一种较为轻量级的同步策略。
*
* 注意: 1. volatile 不具备“互斥性” 2. volatile 不能保证变量的“原子性”
*
* @author yyx 2019年1月12日
*/
public class HaveVolatile {
public static void main(String[] args) {
SubThread subThread = new SubThread();
new Thread(subThread).start(); while (true) {
if (subThread.isFlag()) {
System.out.println("------------------");
break;
}
}
}
} class SubThread implements Runnable {
private volatile boolean flag = false; @Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
flag = true;
System.out.println("flag=" + isFlag());
} public boolean isFlag() {
return flag;
} public void setFlag(boolean flag) {
this.flag = flag;
}
}
运行结果:

flag=true
------------------


注意:volatile不能保证线程的安全

  • volatile不具备“互斥性”
  • volatile不能保证变量的“原子性”

Java多线程-----volatile关键字详解的更多相关文章

  1. Java中Volatile关键字详解 (转自郑州的文武)

    java中volatile关键字的含义:http://www.cnblogs.com/aigongsi/archive/2012/04/01/2429166.html 一.基本概念 先补充一下概念:J ...

  2. Java中Volatile关键字详解

    一.基本概念 先补充一下概念:Java并发中的可见性与原子性 可见性: 可见性是一种复杂的属性,因为可见性中的错误总是会违背我们的直觉.通常,我们无法确保执行读操作的线程能适时地看到其他线程写入的值, ...

  3. Java中Volatile关键字详解(转载)

    转载自:https://www.cnblogs.com/zhengbin/p/5654805.html 一.基本概念 先补充一下概念:Java 内存模型中的可见性.原子性和有序性. 可见性: 可见性是 ...

  4. Java volatile关键字详解

    Java volatile关键字详解 volatile是java中的一个关键字,用于修饰变量.被此关键修饰的变量可以禁止对此变量操作的指令进行重排,还有保持内存的可见性. 简言之它的作用就是: 禁止指 ...

  5. java continue break 关键字 详解 区别 用法 标记 标签 使用 示例 联系

    本文关键词: java continue break 关键字 详解 区别  用法 标记  标签 使用 示例 联系   跳出循环 带标签的continue和break 嵌套循环  深入continue ...

  6. Java之先行发生原则与volatile关键字详解

    volatile关键字可以说是Java虚拟机提供的最轻量级的同步机制,但是它并不容易完全被正确.完整地理解,以至于许多程序员都习惯不去使用它,遇到需要处理多线程数据竞争问题的时候一律使用synchro ...

  7. Java并发编程:JMM (Java内存模型) 以及与volatile关键字详解

    目录 计算机系统的一致性 Java内存模型 内存模型的3个重要特征 原子性 可见性 有序性 指令重排序 volatile关键字 保证可见性和防止指令重排 不能保证原子性 计算机系统的一致性 在现代计算 ...

  8. Java Volatile 关键字详解

    原文链接:https://www.cnblogs.com/zhengbin/p/5654805.html 一.基本概念 先补充一下概念:Java 内存模型中的可见性.原子性和有序性. 可见性: 可见性 ...

  9. jvm运行机制和volatile关键字详解

    参考https://www.cnblogs.com/dolphin0520/p/3920373.html JVM启动流程 1.java虚拟机启动的命令是通过java +xxx(类名,这个类中要有mai ...

随机推荐

  1. python server

    #!/usr/bin/env python #coding=utf-8 # modifyDate: 20120808 ~ 20120810 # 原作者为:bones7456, http://li2z. ...

  2. word2vec参数理解

    之前写了对word2vec的一些简单理解,实践过程中需要对其参数有较深的了解: class gensim.models.word2vec.Word2Vec(sentences=None,size=10 ...

  3. ansible源码安装

    一.升级python 笔者系统为centos6.5,系统默认安装python2.6,虽然ansible官方文档要求python版本为2.6或2.7,然而许多人都说使用2.6可能出现一系列问题,所以作者 ...

  4. 怎么使用JavaScript进行进制转换

    JS 是一个很神奇的语言,内制的的很多函数可以帮我们进行数(进)制转换: JS中可以直接使用16进制: var a = 0xff; //255 将任意进制字符串转换为十进制,如二进制,八进制,十六进制 ...

  5. pycharm换行

    Pycharm自动换行 只对当前文件有效的操作是菜单栏->View -> Active Editor -> Use Soft Wraps. 要是想对所有文件都起到效果,就要在sett ...

  6. linux dmesg 查看系统故障信息

    dmesg 可以查看linux 内核信息 dmesg’命令设备故障的诊断是非常重要的.在‘dmesg’命令的帮助下进行硬件的连接或断开连接操作时,我们可以看到硬件的检测或者断开连接的信息.‘dmesg ...

  7. Centos安装elasticsearch教程

    elasticsearch安装是ytkah在做laravel电商站内搜索要实现的,通过自己的搜索和学习能力不算很费力解决了.下面就整理一下安装elasticsearch教程,服务器是Centos 7, ...

  8. (转)RBAC权限表的设计

    RBAC(Role-Based Access Control,基于角色的访问控制),就是用户通过角色与权限进行关联.简单地说,一个用户拥有若干角色,每一个角色拥有若干权限.这样,就构造成“用户-角色- ...

  9. python 调用阿里云服务器api创建服务器

    首先安装阿里云SDK pip install aliyun-python-sdk-core pip install aliyun-python-sdk-ecs 可以配合jenkins传递参数 #!/u ...

  10. 【LeetCode每天一题】3Sum Closest(最接近的三数和)

    Given an array nums of n integers and an integer target, find three integers in nums such that the s ...