Java并发编程volatile关键字
volatile理解
Java语言是支持多线程的,为了解决线程并发的问题,在语言内部引入了 同步块 和volatile 关键字机制。volatile具有synchronized关键字的“可见性”,volatile变量对于每次使用,线程都能得到当前volatile变量的最新值,但是没有synchronized关键字的“并发正确性”,也就是说不保证线程执行的有序性。
特性
1、保证内存可见性
各个线程对主内存中共享变量的操作都是各个线程各自拷贝到自己的工作内存操作后再写回主内存中的。这就可能存在一个线程AAA修改了共享变量X的值还未写回主内存中时 ,另外一个线程BBB又对内存中的一个共享变量X进行操作,但此时A线程工作内存中的共享比那里X对线程B来说并不不可见.这种工作内存与主内存同步延迟现象就造成了可见性问题。Java提供了volatile来保证可见性,当一个变量被volatile修饰后,表示着线程本地内存无效,当一个线程修改共享变量后他会立即被更新到主内存中,其他线程读取共享变量时,会直接从主内存中读取。
2、不保证原子性
原子性在一个操作是不可中断的,要么全部执行成功要么全部执行失败。如a++,a+=1就不是原子性操作,volatile不能保证原子性。
3、禁止指令重排序
计算机在执行程序时,为了提高性能,编译器和处理器常常会做指令重排:
1. 单线程环境里面确保程序最终执行结果和代码顺序执行的结果一致.
2. 处理器在进行重新排序是必须要考虑指令之间的数据依赖性
3. 多线程环境中线程交替执行,由于编译器优化重排的存在,两个线程使用的变量能否保持一致性是无法确定的,结果无法预测
代码
保证内存可见性
package com.raicho.mianshi.myvolatile;
public class MyVolatileVisibility {
// private int i;
private volatile int i;
public void changeI(int i) {
this.i = i;
}
public static void main(String[] args) {
// System.out.println("没有加volatile关键字");
MyVolatileVisibility myVolatile = new MyVolatileVisibility();
new Thread(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
myVolatile.changeI(1);
System.out.println(Thread.currentThread().getName()+"修改了i="+myVolatile.i);
},"线程1 ").start();
System.out.println( Thread.currentThread().getName()+"访问 i = "+ myVolatile.i);
while (myVolatile.i == 0) {
}
}
}

当没有加volatile关键字时,当主线程先访问了i值为0,后线程1再进行修改i=1,回到mian线程,并不能察觉到i的值修改为1,然而一直在while循环不能结束,加上volatile关键字就能够检测到其他线程已经将i的值修改为1,结束程序。
不保证原子性
package com.raicho.mianshi.myvolatile;
public class VolatileAtomicity {
volatile int number = 0;
public void addNum(){
number++;
}
public static void main(String[] args) {
VolatileAtomicity va = new VolatileAtomicity();
for (int i = 0; i < 20; i++) {
new Thread(()->{
for (int j = 0; j < 1000; j++) {
va.addNum();
}
},String.valueOf(i)).start();
}
//等等20条线程完成
while (Thread.activeCount() >2){
Thread.yield();
}
System.out.println(Thread.currentThread().getName()+" number = "+va.number);
}
}

通过代码验证并最终number并不能达到20000,证明volatile并不保证原子性操作
解决方案
- 在addNum()方法上加锁synchronized关键字,肯定是可以解决的,但是synchronized加锁太重了,严重降低效率
- 使用AtomicInteger类
package com.raicho.mianshi.myvolatile;
import java.util.concurrent.atomic.AtomicInteger;
public class VolatileAtomicity {
volatile int number = 0;
public void addNum(){
number++;
}
AtomicInteger atomicInteger = new AtomicInteger();
public void addNumAtomicInteger(){
atomicInteger.getAndIncrement();
}
public static void main(String[] args) {
VolatileAtomicity va = new VolatileAtomicity();
for (int i = 0; i < 20; i++) {
new Thread(()->{
for (int j = 0; j < 1000; j++) {
//va.addNum();
va.addNumAtomicInteger();
}
},String.valueOf(i)).start();
}
//等等20条线程完成
while (Thread.activeCount() >2){
Thread.yield();
}
// System.out.println(Thread.currentThread().getName()+" number = "+va.number);
System.out.println(Thread.currentThread().getName()+" number = "+va.atomicInteger);
}
}

禁止指令重排序
public void mySort(){
int x=11;//语句1
int y=12;//语句2
x=x+5;//语句3
y=x*x;//语句4
}
重新排序后可能会变为
1234
2134
1324
问题:
请问语句4 可以重排后变成第一条码?
存在数据的依赖性 没办法排到第一个
单例模式中使用双重检测机制
public class SingletonDemo {
private static volatile SingletonDemo instance=null;
private SingletonDemo(){
System.out.println(Thread.currentThread().getName()+"\t 构造方法");
}
/**
* 双重检测机制
* @return
*/
public static SingletonDemo getInstance(){
if(instance==null){
synchronized (SingletonDemo.class){
if(instance==null){
instance=new SingletonDemo();
}
}
}
return instance;
}
public static void main(String[] args) {
for (int i = 1; i <=10; i++) {
new Thread(() ->{
SingletonDemo.getInstance();
},String.valueOf(i)).start();
}
}
}
在多线程下,不加volatile关键字也可能出现指令重排的情况,是线程不安全的
Java并发编程volatile关键字的更多相关文章
- Java并发编程 Volatile关键字解析
volatile关键字的两层语义 一旦一个共享变量(类的成员变量.类的静态成员变量)被volatile修饰之后,那么就具备了两层语义: 1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了 ...
- java并发编程 volatile关键字 精准理解
1.volatile的作用 一个线程共享变量(类的成员变量.类的静态成员变量等)被volatile修饰之后,就具有以下作用: 1)并发中的变量可见性(不同线程对该变量进行操作时的可见性),即一个线程修 ...
- Java 并发:volatile 关键字解析
摘要: 在 Java 并发编程中,要想使并发程序能够正确地执行,必须要保证三条原则,即:原子性.可见性和有序性.只要有一条原则没有被保证,就有可能会导致程序运行不正确.volatile关键字 被用来保 ...
- java并发系列(六)-----Java并发:volatile关键字解析
在 Java 并发编程中,要想使并发程序能够正确地执行,必须要保证三条原则,即:原子性.可见性和有序性.只要有一条原则没有被保证,就有可能会导致程序运行不正确.volatile关键字 被用来保证可见性 ...
- 一起来看看java并发中volatile关键字的神奇之处
并发编程中的三个概念: 1.原子性 在Java中,对基本数据类型的变量的读取和赋值操作是原子性操作,即这些操作是不可被中断的,要么执行,要么不执行. 2.可见性 对于可见性,Java提供了volati ...
- java并发:volatile关键字
java并发需要保证原子性,可见性,有序性. http://www.cnblogs.com/expiator/p/9226775.html 一.volatile关键字作用如下: 1.volatile关 ...
- Java 并发编程——volatile与synchronized
一.Java并发基础 多线程的优点 资源利用率更好 程序设计在某些情况下更简单 程序响应更快 这一点可能对于做客户端开发的更加清楚,一般的UI操作都需要开启一个子线程去完成某个任务,否者会容易导致客户 ...
- Java多线程编程——volatile关键字
(本篇主要内容摘自<Java多线程编程核心技术>) volatile关键字的主要作用是保证线程之间变量的可见性. package com.func; public class RunThr ...
- Java并发编程--Volatile详解
摘要 Volatile是Java提供的一种弱同步机制,当一个变量被声明成volatile类型后编译器不会将该变量的操作与其他内存操作进行重排序.在某些场景下使用volatile代替锁可以减少 ...
随机推荐
- JQuery学习(一)
本文是学习廖老师的Javascript全栈教程后的一些笔记. 使用jQuery: 方法一:下载jQuery库,并在html页面中引入,方式如下: 1 <html> 2 <head&g ...
- Netflix:当你按下“播放”的时候发生了什么?
从用户端来看,使用Netflix是很简单的,按下播放键之后视频就像变魔术一样完美呈现了.看起来很容易是吧?然而实际不是这样的.了解过云计算的人可能会简单地以为,既然Netflix使用AWS来提供视频服 ...
- 【万字长文】别再报班了,一篇文章带你入门Python
本文始发于个人公众号:TechFlow,原创不易,求个关注 最近有许多小伙伴后台联系我,说目前想要学习Python,但是没有一份很好的资料入门.一方面的确现在市面上Python的资料过多,导致新手会不 ...
- TOP-K Problems
最小的K个数 直接数组排序,取出前K个.复杂度\(O(nlogn)\). 分治 此题只要求出最小的K个数,并不要求这K个数有序. 我们可以借鉴快排中的partition做法,将比第K个数小的都放前面, ...
- 图论-欧拉图-欧拉回路-Euler-Fluery-Hierholzer-逐步插入回路法-DFS详解-并查集
欧拉图性质: 1.无向连通图G是欧拉图,当且仅当G不含奇数度结点(G的所有结点度数为偶数): 2.无向连通图G含有欧拉通路,当且仅当G有零个或两个奇数度的结点: 3.有向连通图D是欧拉图,当且仅当该图 ...
- 【WPF学习】第六十八章 自定义绘图元素
上一章分析了WPF元素的内部工作元素——允许每个元素插入到WPF布局系统的MeasureOverride()和ArrangeOverride()方法中.本章将进一步深入分析和研究元素如何渲染自身. 大 ...
- airtest+poco多脚本、多设备批处理运行测试用例自动生成测试报告
一:主要内容 框架功能及测试报告效果 airtest安装.环境搭建 框架搭建.框架运行说明 airtest自动化脚本编写注意事项 二:框架功能及测试报告效果 1. 框架功能: 该框架笔者用来作为公司的 ...
- PLAI那些事_06 FAE
没有了with表达,with,exp,body的id换成exp的lambda函数,从而可以没有with来进行实现.即,{with {id exp} body}换成了{{fun {id} body} e ...
- 模块(类)之间解耦利器:EventPublishSubscribeUtils 事件发布订阅工具类
如果熟悉C#语言的小伙伴们一般都会知道委托.事件的好处,只需在某个类中提前定义好公开的委托或事件(委托的特殊表现形式)变量,然后在其它类中就可以很随意的订阅该委托或事件,当委托或事件被触发执行时,会自 ...
- Educational Codeforces Round 77 (Rated for Div. 2) C. Infinite Fence
C. Infinite Fence 题目大意:给板子涂色,首先板子是顺序的,然后可以涂两种颜色,如果是r的倍数涂成红色,是b的倍数涂成蓝色, 连续的k个相同的颜色则不能完成任务,能完成任务则输出OBE ...