并发编程(三大特性)-volatile

1:可见性

         是指当一个线程对共享变量进行了修改,那么另外的线程可以立即看到修改后的最新值。
以上运行结果

2:原子性

        在一次或多次操作中,要么所有的操作都执行 并且不会受其他因素干扰而中断,要么所有的操作都不执行

使用一千个线程每个线程对count作++来修改count的值

3:有序性

        保证程序按照正确的顺序执行。实现禁止指令重排序可以通过 volatile 添加内存屏障happens-before 保证顺序性。

不影响单线程程序执行结果的前提下,计算机为了最大限度的发挥计算性能,会对及其指令重排序优化

package com.sync;

import java.util.concurrent.TimeUnit;

public class Demo1 {
    static boolean flag = false;
    public static void main(String[] args) throws InterruptedException {

        new Thread("t1"){
            public void run(){
                System.out.println(Thread.currentThread().getName()+"--开始运行");
                while(!flag){  //自旋
                    //不写任何输出
                }
                System.out.println(Thread.currentThread().getName()+"--停止运行");
            }
        }.start();

        //保证t2在t1之后运行,在这里延时一秒钟
        TimeUnit.SECONDS.sleep(1);

        //使用t2线程修改flag变量-->true
        new Thread("t2"){
            public void run(){
                flag = true;
                System.out.println(Thread.currentThread().getName()+"--把flag改为了true");
            }
        }.start();
    }
}

结果
t1--开始运行
t2--把flag改为了true

t2把flag改成了true,但是t1线程读不到flag的改变值,一直陷入死循环(自旋),说明flag参数在两个线程中不可见

4:JAVA内存模型(Java Memory Model即JMM)

        JAVA多线程内存模型是基于CPU缓存模型来建立的,JAVA线程内存模型是标准化的,屏蔽掉了底层不同计算机的区别

Java 线程之间的通信由 Java 内存模型(JMM)控制,JMM 决定一个线程对共享变量的写入何时对另外一个线程可见。从抽象角度来看,JMM 定义了线程和主内存(内存条)之间的抽象关系:

线程之间的共享变量存储在主内存(Main Memory内存条)中,每个线程都有一个私有的本地内存(Local Memory),本地内存中存储了该线程以读/写共享变量的副本。本地内存是JMM 的一个抽象概念,并不真实存在。它涵盖了缓存、写缓冲区、寄存器以及其他的硬件和编译器优化。
 


 

主内存中的flag值被线程t2修改了,但在线程t1中的flag并没有改变,所以线程t1一致在死循环中没有结束

原因:

        这是因为flag申明是在主内存中,每个线程中的有一块”本地内存”存储了flag的副本,虽然通过线程B把主内存中的flag修改了,但是线程A的工作内存中的值并没有改
//加了volatile 之后发现t1线程跳出死循环结束
static volatile boolean flag = true; 

volatile 修饰的变量进行被修改时,JVM 会向处理器发送一条 Lock# 前缀的指令,将这个变量所在缓存行的数据写回到系统主内存,同时其他 CPU 里缓存该内存地址的数据无效。线程在进行读操作时,发现本地内存无效,然后从主内存获取最新的数据,从而保证多核 CPU 以及多线程的数据可见性。
 

5:为什么加了volatile就可以让线程t1中能感知主内存数据的改变呢?


通过以下MESI(缓存一致性协议)和缓存加锁实现
 

1缓存一致性协议(MESI)

多个CPU或多条线程从主内存读取同一个数据到各自的高速缓存,当其中某个CPU修改了缓存里的数据,该数据会马上同步回主内存,其他CPU(线程)通过总线(即Bus是计算机各种功能部件之间传送信息的公共通信干线)嗅探机制可以感知到数据的变化从而将自己缓存里的数据失效

2缓存加锁

缓存锁的核心机制是基于缓存一致性协议来实现的,一个处理器的缓存会写到主内存会导致其他处理器的缓存无效,IA-32和Intel64处理器使用MESI实现缓存一致性

3Volatile底层原理

线程B中识别到有volatile修饰flag后,底层通过汇编语言锁定(lock) volatile修饰的变量,称为:”缓存行锁定”,然后把更新的值立即同步到主内存,这个操作会引起其他CPU中缓存了该内存地址的数据无效,其他CPU中的线程A就会重新发起read从主内存中取数据,这样就实现了缓存一致
图解volatile 
 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值