多线程《1》JMM基础知识---volatile的可见性和一致性

JMM

    • 引出线程的不可见性
    • jmm的八个原子性操作
    • volatile 可见性
    • volatile 实现顺序一致性

前言:
jvm是java虚拟机用于解释,编译执行java代码,jvm可以再不同的操作系统上执行并且提供了内存管理,垃圾回收等
jmm是java中多线程对于内存共享的行为规范,规定了在多线程环境下如何正确的使用共享变量,jmm定义了变量的可见性,原子性和有序性等特征,

引出线程的不可见性

  • 众所周知,电脑只会有一个主内存和多个cpu,多个cpu想拿到主内存的数据,并不是直接去访问主内存的,需要通过cpu缓存去拿主内存的数据
    图下所示:
    多线程《1》JMM基础知识---volatile的可见性和一致性_第1张图片
  • java多线程的内存标准和cpu缓存模型类似,是基于cpu缓存模型建立的
  • 如下图所示:主内存中存储的是isflag=true,每一个线程的工作内存会生成一个副本isflag=true
  • 如果线程1修改了值变为了isfalg=fase,那么他修改的对于另外一个线程是不可见的,另外一个线程取的是工作内存中的值
  • 线程1的工作内存是isflag=false 线程2的工作内存中的值是isflag==true,线程之间是不可见的
    多线程《1》JMM基础知识---volatile的可见性和一致性_第2张图片
  • 代码演示
public class VolatileThread extends   Thread{

    public  boolean isflag=true;
//public  volatile boolean isflag=true;

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"子线程开始执行...");
        while (isflag) {

        }
        System.out.println(Thread.currentThread().getName()+"子线程执行结束...");
    }


    public void setRuning(boolean  isflag)
    {
        System.out.println("修改值");
        this.isflag = isflag;
    }
}

public class ThreadVolatile {
    public static void main(String[] args) throws InterruptedException {

        //实例化
        VolatileThread volatileThread=new VolatileThread();
        //启动线程
        volatileThread.start();

        Thread.sleep(3000);
        //睡眠3s后,main线程调用修改状态的方法
        volatileThread.setRuning(false);



    }
}

  • 线程1初始值是true,然后顺利的进入的死循环,然后 volatileThread.setRuning(false); 修改为false了,正常情况下程序应该结束,但是Thread-0读取的是副本的值,并不是直接读取的主内存的值,所以main线程修改的值,他是不可见的,如何解决这个问题?将isflag用volatile修饰
    多线程《1》JMM基础知识---volatile的可见性和一致性_第3张图片

jmm的八个原子性操作

  • 作可以确保多线程环境下的数据同步和一致性,保证对共享资源的操作是原子性的,避免了并发问题的发生。
  • read(r读取):从主内存中读取数据
  • load(载入)将主内存读取到的数据写入工作内存
  • use(使用)从工作内存读取数据来计算
  • assign(赋值)将计算好的值重新赋到工作变量中
  • store(存储)将工作内存数据写入到主内存
  • write(写入)将store过去的变量赋值给主内存
  • lock(锁定)将主内存变量加锁,标识位线程独占状态
  • unlock(解锁)将主内存变量解锁,解锁后其他线程可以锁定该变量
    多线程《1》JMM基础知识---volatile的可见性和一致性_第4张图片
    了解:
  • 缓存一致性协议
    多个cpu从主内存读取同一个数据到各自高速缓存当其中的某个cpu修改了数据该数据会马上同步回主内存,其他cpu会通过总线嗅探机制可以感知到数据的变化,从而改变自己工作区间的数据
  • 总线嗅探机制
    -总线嗅探机制是一种硬件机制,用于实现多个cpu共享数据的一致性,当一个cpu修改了数据并将其写入到了主内存中,其他cpu通过监听总线上的数据传输,可以感知到数据的变化。多个cpu从主内存读取同一个数据到各自高速缓存当其中的某个cpu修改了数据该数据会马上同步回主内存,其他cpu会通过总线嗅探机制可以感知到数据的变化,从而改变自己工作区间的数据
  • 思考:为什么线程2修改了数据,线程1会知道,并同步数据,其过程是什么样子的?
  • 原本isfllag-true 线程2通过store和write去修改isflag=false并写入到主内存中,需要经过数据总线,因为总线嗅探机制存在多个cpu去监控数据总线,当线程2修改数据经过数据总线的时候,被监控到了,其他cpu发现自己的工作空间也有isflag这个变量,就会失效,当use使用的时候,发现失效了,找不到了就会重新去主内存加载,这就是数据同步

volatile 可见性

  • 使用volatile 会使缓存一致性生效,只有缓存一致性生效,其他cpu才可以快速感知到数据的变化,从而让自己副本的数据失效,重新前往主内存拿数据
  • 底层主要是通过汇编lock前缀指令,他会锁定这块区域的缓存(缓存行锁定),并写回主内存

volatile 实现顺序一致性

使用volatile的时候会加lock,在底层加上了lock的话就不会进行充排序了,这样就实现了顺序一致性(预计以后会写这个详细的)

你可能感兴趣的:(JAVA进阶,java)