Java多线程-----volatile关键字详解
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关键字详解的更多相关文章
- Java中Volatile关键字详解 (转自郑州的文武)
java中volatile关键字的含义:http://www.cnblogs.com/aigongsi/archive/2012/04/01/2429166.html 一.基本概念 先补充一下概念:J ...
- Java中Volatile关键字详解
一.基本概念 先补充一下概念:Java并发中的可见性与原子性 可见性: 可见性是一种复杂的属性,因为可见性中的错误总是会违背我们的直觉.通常,我们无法确保执行读操作的线程能适时地看到其他线程写入的值, ...
- Java中Volatile关键字详解(转载)
转载自:https://www.cnblogs.com/zhengbin/p/5654805.html 一.基本概念 先补充一下概念:Java 内存模型中的可见性.原子性和有序性. 可见性: 可见性是 ...
- Java volatile关键字详解
Java volatile关键字详解 volatile是java中的一个关键字,用于修饰变量.被此关键修饰的变量可以禁止对此变量操作的指令进行重排,还有保持内存的可见性. 简言之它的作用就是: 禁止指 ...
- java continue break 关键字 详解 区别 用法 标记 标签 使用 示例 联系
本文关键词: java continue break 关键字 详解 区别 用法 标记 标签 使用 示例 联系 跳出循环 带标签的continue和break 嵌套循环 深入continue ...
- Java之先行发生原则与volatile关键字详解
volatile关键字可以说是Java虚拟机提供的最轻量级的同步机制,但是它并不容易完全被正确.完整地理解,以至于许多程序员都习惯不去使用它,遇到需要处理多线程数据竞争问题的时候一律使用synchro ...
- Java并发编程:JMM (Java内存模型) 以及与volatile关键字详解
目录 计算机系统的一致性 Java内存模型 内存模型的3个重要特征 原子性 可见性 有序性 指令重排序 volatile关键字 保证可见性和防止指令重排 不能保证原子性 计算机系统的一致性 在现代计算 ...
- Java Volatile 关键字详解
原文链接:https://www.cnblogs.com/zhengbin/p/5654805.html 一.基本概念 先补充一下概念:Java 内存模型中的可见性.原子性和有序性. 可见性: 可见性 ...
- jvm运行机制和volatile关键字详解
参考https://www.cnblogs.com/dolphin0520/p/3920373.html JVM启动流程 1.java虚拟机启动的命令是通过java +xxx(类名,这个类中要有mai ...
随机推荐
- PLSQL游标
静态游标:结果集已经确实(静态定义)的游标.分为隐式和显式游标 隐式游标:所有DML语句为隐式游标,通过隐式游标属性可以获取SQL语句信息: 显式游标:用户显式声明的游标,即指定结果集.当查询返回结果 ...
- LeetCode 811 Subdomain Visit Count 解题报告
题目要求 A website domain like "discuss.leetcode.com" consists of various subdomains. At the t ...
- 安装IIS
1.打开控制面板,找到“程序与功能”,点进去 2.选择打开或关闭Windows功能,选择internet信息服务,点击确定 3.安装完成后,再回到控制面板里面,找到“管理工具”,点进入 4.双击“I ...
- java web指定主页
正常情况下主页是在web.xml里面配置欢迎页面,可以加个过滤器重定向就可以: public void doFilter(ServletRequest req, ServletResponse res ...
- 对线程发送signal
学习对线程 发送 signal #include <stdio.h> #include <stdlib.h> #include <string.h> #includ ...
- zip压缩类
using System; using System.Collections.Generic; using System.Text; using System.Text.RegularExpressi ...
- GUI库之认识Tkinter(一)
一.介绍 Tkinter是Python默认的GUI库,我们经常使用的IDLE就是用Tkinter设计出来的,因此我们在使用的时候直接导入Tkinter模块就好了. 1.特点:可移植性.灵活性高 2.构 ...
- Mysql索引详细语法
索引相关命令 - 查看表结构 desc 表名 - 查看生成表的SQL show create table 表名 - 查看索引 show index from 表名 - 查看sql执行时间 set pr ...
- 为chrome设置代理
1:打开google>setting>proxy ,点击局域网设置. 2: 设置代理,当使用代理访问不了公司的网络时,需要将代理勾掉,将上面的公司用的网选上.
- ipfs私链服务
cd /lib/systemd/system vi ipfs.service [Unit]Description=IPFS[Service]ExecStart=/usr/bin/ipfs daemon ...