• 并发编程之Java内存模型


      在介绍Java内存模型之前,先来了解一下为什么要有内存模型,以及内存模型是什么。然后我们基于对内存模型的了解,学习Java内存模型以及并发编程的三大特性。

    为什么要有内存模型

      在计算机中,所有的运算操作都是由CPU的寄存器来完成的,CPU指令的执行需要涉及到数据的读写操作,而CPU只能访问主存中的数据。随着技术的发展,CPU的执行速度越来越快,而内存的访问速度没有太大的变化,导致CU每次操作主存都要等待很长的时间。于是就有了在CPU与主存之间添加缓存的设计。

    内存模型:CPU Cache模型

     

      目前缓存的数量达到了3级,最接近CPU的缓存称为L1,然后为L2、L3和主存。由于程序指令和数据的行为和热点分布差异比较大,因此将L1又细分为L1i(istruction)、L1d(data)。

       CPU的出现是为了解决CPU直接访问主存效率低下的问题。程序在运行过程中,会将运算所需的数据从主存中复制一份到Cache中,这样CPU在计算时就可以直接对CPU Cache中的数据进行读写,当运算结束后,再将Cahce中的最新数据刷新到主存中。
     
      虽然缓存的出现极大地提升了CPU的吞吐能力,但是也导致了缓存不一致的问题。这是因为CPU都是对Cache中的数据进行读写,不同线程之间的工作内存是相互独立的,对某个线程工作空间中的数据进行更新,可能会无法及时同步到其它缓存中。
     
      为了保证数据的正确性,内存模型定义了共享内存系统中多线程程序读写操作行为的规范。

    Java内存模型

        Java内存模型(Java Memory Model ),简称JMM,是一种符合内存模型规范的,屏蔽了各种硬件和操作系统的访问差异的,保证了Java程序在各种平台下对内存的访问都能得到一致效果的机制及规范。其目的是解决多线程通过主内存进行通信时,存在的原子性、可见性(缓存一致性)以及有序性问题。(关于原子性、可见性(缓存一致性)以及有序性,我们将会在”并发编程的三大特性“中详细讲解)
     
        JMM决定了一个线程对共享变量的写入何时对其它线程可见,定义了线程与主存之间的关系:
    • 共享变量存储于主存中,每个线程都可以访问
    • 每个线程都有私有的工作内存,也称为本地内存
    • 工作内存中只存储共享变量的副本
    • 线程不能直接操作主存,只有操作了本地内存后才能写入主存
    • 每一个线程都不能访问其他线程的本地内存
     

     并发编程的三大特性

        并发编程有三大特性:原子性、可见性、有序性。
      •   原子性:是指在一次操作或多次操作中,要么所有的操作都得到执行,要么都不执行。【类似于事务】
        •   JMM只保证了基本读取和赋值的原子性操作
        •   多个原子性操作的组合不再是原子性操作
        •   可以使用synchronized/lock保证某些代码片段的原子性
        •   对于int等类型的自增操作,可以通过java.util.concurrent.atomic.*保证原子性
      •   可见性:是指一个线程对共享变量进行了修改,其他线程可以立即看到修改后的值。
      •   有序性:是指代码在执行过程中的先后顺序是有序的。【Java编译器会对代码进行优化,执行顺序可能与开发者编写的顺序不同(指令重排)】
     
      并发编程时,保证三大特性的方式有三种:
      •   使用volatile关键字修饰变量
        •   当一个变量被volatile关键字修饰时,对于共享变量的读操作会直接在主存中进行,对于共享变量的写操作是先修改本地内存,修改结束后直接刷到主存中。(未被volatile修饰的变量被修改后,什么时候最新值会被刷到主存中是不确定的)
      •   使用synchronized关键字修饰方法或代码块
        •   synchronized关键字能保证同一时刻只有一个线程获得锁然后执行同步方法,并且确保锁释放之前,会将修改的变量刷入主存。
      •   使用JUC提供的显式锁Lock
        •   Lock能保证同一时刻只有一个线程获得锁然后执行同步方法,并且确保锁释放之前,会将修改的变量刷入主存。

     补充

      Java中提供了一系列和并发处理相关的关键字,比如volatile、synchronized等,其实这些就是Java内存模型封装了底层的实现后提供给程序员使用的一些关键字。

    参考文献

    • 汪文君《Java高并发编程详解-多线程与架构设计》
  • 相关阅读:
    设计模式面试题(总结最全面的面试题!!!)
    一文彻底搞懂CAS实现原理
    从前慢ShardingJDBC
    Azure Storage (30) Azure Storage费用和事务相关的问题
    数据库界的Swagger:一键生成数据库文档!
    异步编程利器:CompletableFuture
    Android recyclerview的滑动到指定的item
    android 获取 item的位置,RecyclerView 滚动和获取指定位置Item的完整方案
    Android Recyclerview适配器 加载头部 以及自定义View
    基础python的快速学习
  • 原文地址:https://www.cnblogs.com/BlueStarWei/p/11278621.html
Copyright © 2020-2023  润新知