zoukankan      html  css  js  c++  java
  • 并发编程:JAVA并发编程的一些基础原理

    Volatile关键字

    保证线程间共享变量的可见性、有序性。
    如何保证可见性:多了一个Lock的汇编指令。

    什么是可见性
    • 硬件
      • 运行速度:CPU > 内存 > IO设备;所以在硬件的使用中,为了提高效率
        • CPU增加了高速缓存
          • 读数据时,从内存读,然后缓存到CPU缓存,线程修改变量时会先同步到缓存,再同步到主内存。这时候会出现缓存一致性问题,CPU层面解决该问题的方案是总线锁,缓存锁。
          • 缓存一致性协议(MESI)S:Shared;E:Exclusive;I:Invalid;M:Modify。缓存处于I状态时,必须去主内存读;缓存处于S状态时,写数据必须先让其他CPU缓存变为I状态。
          • MESI协议又会导致在Invalidate其他线程变量时有阻塞,引入了storebuffer,指令写入到storebuffer,降低阻塞。但是这又会导致执行乱序,引发新的可见性问题。CPU层面提供了指令->内存屏障来解决可见性问题。三种屏障:写屏障(之前的结果必须对后面可见)、读屏障(读屏障之后的指令一定能读到最新数据)、全屏障。
        • 引入线程、进程
        • 指令优化:重排序
    • JMM(Java Memory Model)
      • 为了解决平台差异化的问题,Java提供了JMM(语言级别的抽象内存模型),核心价值是解决了可见性和有序性的问题。
      • 概念
        • 工作内存:线程本地内存
        • 主内存:线程共享的内存
        • 线程会先读工作内存,再读主内存。在这种情况下,还是会存在可见性问题。为了解决这些问题,java引入了jvm级别的4种屏障:loadload,storestore,loadstore,storeload
          • loadload:该屏障之前的读一定能被后面读到
          • storestore:前面的写先于后面的写(后面写能知道前面的写)
          • loadsotre:前面的读先于后面的写(后面能写到前面的读)
          • storeload:前面的写先于后面的读(后面能读到前面的写)
            还引入了volatile、synchronized、final、happens-before一些关键字和原则。
        • 重排序:java源代码->编译期重排序->cpu重排序->最终执行的顺序;重排序不能改变程序单线程运行下的结果(as-if-serial)。
      • volatile
        • volatile通过语言级别的屏障指令,保证缓存每次都被刷到主内存,读取均从主内存读,来保证可见性
        • volatile同时还保证了有序性(经典用法就是解决double-check单例模式对象new过程中的重排序)
        • volatile不能保证原子性
      • happens-before原则
        • 1、程序的顺序规则:一个线程中的任意操作,happens-before于该线程中的任意后续操作。
        • 2、volatile规则:对一个volatile字段的写,happens-before于任意后续对该字段的读。
        • 3、传递性规则:如果A happens-before B,B happens-before C,那么A一定 happens-before C。
        • 4、start()规则:如果A线程操作执行B线程的start(),那么A线程的B.start() happens-before B线程中的任意操作。
        • 5、join()规则:如果A线程执行操作B线程的join()并成功返回,那么B线程的任意操作一定happens-before 线程A的 B.join()。
        • 6、监视器锁规则:对锁的释放 happens-before 后续对该锁的获取。
        • 7、程序中断规则:线程A对线程B interrupted()调用 happens-before B线程检测到被中断线程的中断时间(抛出interruptException)。
        • 8、对象finalize规则:对象的初始化完成 happens-before 它的finalize()方法。
  • 相关阅读:
    二、DBMS_JOB(用于安排和管理作业队列)
    Oracle 常用系统包
    DBMS_OUTPUT(用于输入和输出信息)
    C#获取当前主机硬件信息
    Centos安装mysql5.7
    Rsync安装和配置
    利用Docker编译Hadoop 3.1.0
    hadoop集群环境搭建
    axios请求、拦截器
    import时,什么时候使用花括号'{ }'
  • 原文地址:https://www.cnblogs.com/fcb-it/p/13284131.html
Copyright © 2011-2022 走看看