java关键字-volatile

前言
  • java 5之前这个关键字备受争议,java5只有volatile才得以重生
  • 因为volatile和java的内存模型有关(想弄清楚volatile就必须弄清相关的内存模型)
java相关的内存模型的概念
  • 程序运行时临时数据存放在主存(物理内存中)
  • cpu 在告诉运作时cpu存在高速缓存
  • 就存在高速缓存和内存之间的数据交互
  • 问题:数据的高并发同步问题
并发编程的三个概念
  • 原子性
    一个操作或者多个操作,要么全部执行,要么都不执行称为一个程序的原子性

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

  • 有序性
    程序执行的顺序按照代码的编写顺序执行(因为在代码执行阶段,处理器会对代码进行重排,但是这并不影响代码的最终执行结果)

java 内存模型

从代码层面分析前面提的三个概念

  • 分析代码的原子性操作
x = 10;         //语句1
y = x;         //语句2
x++;           //语句3
x = x + 1;     //语句4

语句1是直接将数值10赋值给x,也就是说线程执行这个语句的会直接将数值10写入到工作内存中。
语句2实际上包含2个操作,它先要去读取x的值,再将x的值写入工作内存,虽然读取x的值以及 将x的值写入工作内存 这2个操作都是原子性操作,但是合起来就不是原子性操作了。
同样的,x++和 x = x+1包括3个操作:读取x的值,进行加1操作,写入新的值。
所以上面4个语句只有语句1的操作具备原子性。
总结:
java内存模型只保证了基本读取和赋值是原子性操作,如果要实现更大范围操作的原子性,可以通过synchronized和lock来实现,(因为锁可以保证同一时刻只有一个线程执行该代码块,从而保证了原子性)

  • 可见性
    1、对于可见性,volatile关键字来保证可见性
    当一个共享变量被volatile修饰时,他会保证修改的值会立即被更新到主存,当有其他线程读取时,他会去主存内从新读取
    2、而普通的共享变量不能保证可见性,因为不能保证什么时候写入朱存
    3、利用锁可以实现变量的可见性,因为在synchronized和lock能保证同一时刻只有一个线程获取锁执行同步代码,并且在释放锁之前会将变量的修改刷新到朱存当中来保证可见性;

  • 有序性
    在java内存模型中,允许编译器和处理器对指令进行重排,但是重排过程不会影响单线程的执行,却会影响多线程的并发执行顺序
    1、 java中 可以通过volatile关键字来保证有序性
    2、当然也可通过synchronized和lock来保证有序性
    3、java 先天存在happens-before原则,

剖析volatile的关键字

一旦一个变量被volatile修饰,就具备以下两种含义
1、 保证了不同线程对于这个变量进行操作时的可见性
2、禁止指令重排
注意:维度不能保障原子性,
首先先看个代码

//线程1
boolean stop = false;
while(!stop){
    doSomething();
}
 
//线程2
stop = true;

很多人都会这么干,但是这个会不会出错呢?答案是会出错的,因为线程中的数据和全局的数据是一样的吗?
解决的话 就是在stop 前面添加volatile关键字,他会在线程刷新数据的时候立马改变共享内存的数据
所以说:volatile无法保证原子性

  • volatile保障原子性?
    无法保障
    如果想保障程序的原子性 可依靠sychronized或者lock 来实现

  • volatile保障可见性

public class Test {
    public volatile int inc = 0;
     
    public void increase() {
        inc++;
    }
     
    public static void main(String[] args) {
        final Test test = new Test();
        for(int i=0;i<10;i++){
            new Thread(){
                public void run() {
                    for(int j=0;j<1000;j++)
                        test.increase();
                };
            }.start();
        }
         
        while(Thread.activeCount()>1)  //保证前面的线程都执行完
            Thread.yield();
        System.out.println(test.inc);
    }
}

这串代码就能保证最后的结果是10000吗?答案也是no
因为虽然说线程在执行的时候会立马更新主存的数据,但是数据的++本身分为两个步骤,所以无法达到理想效果
1、可采用java atomic 包下面的 atomicinteger 的增加来计算
2、利用synchronized 和 lock 来实现原子性
总结:volatile实现可见性,是一个线程(cpu)的数据改变,他会更新主存的数据改变,同时他会让其他线程(cpu)的数据失效。

  • volatile保证有序性
    线程中的顺序 会以volatile为分界,按顺序执行
//x、y为非volatile变量
//flag为volatile变量
 
x = 2;        //语句1
y = 0;        //语句2
volatile flag = true;  //语句3
x = 4;         //语句4
y = -1;       //语句5

分析:1、2是一组 谁在前谁在后不一定
但是一定会在3前,同理,3肯定在4、5的前面,
4、5谁在前谁在后不一定

volatile的应用场景
  • synchronizd关键字是防止多个线程同时执行一段代码,那么他会很影响程序执行的效率,而volatile关键字在某些方面优于synchronized,但是注意volatile关键字无法替代synchronized关键字的,因为volatile无法保证程序的原子性,
  • 通常使用volatile有以下2个条件:
    1、对变量的改变不依赖于当前值
    2、对变量的依附不依赖于其他对象
    示例:
volatile boolean flag = false;
 
while(!flag){
    doSomething();
}
 
public void setFlag() {
    flag = true;
}
volatile boolean inited = false;
//线程1:
context = loadContext();  
inited = true;            
 
//线程2:
while(!inited ){
sleep()
}
doSomethingwithconfig(context);

一般都是作为多线程标记用的

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容