在介绍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高并发编程详解-多线程与架构设计》

并发编程之Java内存模型的更多相关文章

  1. 并发编程之 Java 内存模型 + volatile 关键字 + Happen-Before 规则

    前言 楼主这个标题其实有一种作死的味道,为什么呢,这三个东西其实可以分开为三篇文章来写,但是,楼主认为这三个东西又都是高度相关的,应当在一个知识点中.在一次学习中去理解这些东西.才能更好的理解 Jav ...

  2. 并发编程之java内存模型(Java Memory Model ,JMM)

    一.图例 0.两个概念 Heap(堆):运行时的数据区,由垃圾回收负责,运行时分配内存(所以慢),对象存放在堆上 如果两个线程,同时调用同一个变量,怎两个线程都拥有,该对象的私有拷贝 (可以看一下,T ...

  3. 《深入了解java虚拟机》高效并发读书笔记——Java内存模型,线程,线程安全 与锁优化

    <深入了解java虚拟机>高效并发读书笔记--Java内存模型,线程,线程安全 与锁优化 本文主要参考<深入了解java虚拟机>高效并发章节 关于锁升级,偏向锁,轻量级锁参考& ...

  4. Java并发编程(1)-Java内存模型

    本文主要是学习Java内存模型的笔记以及加上自己的一些案例分享,如有错误之处请指出. 一 Java内存模型的基础 1.并发编程模型的两个问题 在并发编程中,需要了解并会处理这两个关键问题: 1.1.线 ...

  5. 并发研究之Java内存模型(Java Memory Model)

    Java内存模型JMM java内存模型定义 上一遍文章我们讲到了CPU缓存一致性以及内存屏障问题.那么Java作为一个跨平台的语言,它的实现要面对不同的底层硬件系统,设计一个中间层模型来屏蔽底层的硬 ...

  6. 高并发和多线程——Java内存模型

    个人理解: 1.并发编程分为三个核心:分工.同步.互斥 2.CPU.内存.I/O存在速度差异问题. 3.线程切换导致原子性问题.编译优化导致有序性问题.缓存导致可见性问题. 4.Java内存模型规范了 ...

  7. 【Java并发系列】--Java内存模型

    Java内存模型 1 基本概念 程序:代码,完成某一个任务的代码序列(静态概念) 进程:程序在某些数据上的一次运行(动态) 线程:一个进程有一个或多个线程组成(占有资源的独立单元) 2 JVM与线程 ...

  8. 【Java并发基础】Java内存模型解决有序性和可见性

    前言 解决并发编程中的可见性和有序性问题最直接的方法就是禁用CPU缓存和编译器的优化.但是,禁用这两者又会影响程序性能.于是我们要做的是按需禁用CPU缓存和编译器的优化. 如何按需禁用CPU缓存和编译 ...

  9. Java并发编程:Java内存模型JMM

    简介 Java内存模型英文叫做(Java Memory Model),简称为JMM.Java虚拟机规范试图定义一种Java内存模型来屏蔽掉各种硬件和系统的内存访问差异,实现平台无关性. CPU和缓存一 ...

随机推荐

  1. net开发框架never

    [一] 摘要 never是纯c#语言开发的一个框架,同时可在netcore下运行. 该框架github地址:https://github.com/shelldudu/never 同时,配合never_ ...

  2. ubuntu16.04基本设置

    1. ubuntu16.04开启ssh https://jingyan.baidu.com/article/f54ae2fc6f9eef1e93b8497a.html 2. windows 远程桌面连 ...

  3. visudo 与 /etc/sudoers

    增加多个用户免密码登录 User_Alias USER_OPS = zouyi,hanerhui,shibeibei,gaoxudong,xiaoyuelin,wangsongfeng,sunjian ...

  4. windows container 踩坑记

    windows container 踩坑记 Intro 我们有一些服务是 dotnet framework 的,不能直接跑在 docker linux container 下面,最近一直在折腾把它部署 ...

  5. 【linux杂谈】在SSH连接中,openssh如何解决'Connection refused'错误?

    openssh是SSH (Secure SHell) 协议的免费开源实现.SSH协议族可以用来进行远程控制, 或在计算机之间传送文件. 这就意味着远程登陆,文件推拉特别是搭建集群后公钥的部署,经常要利 ...

  6. Oracle数据库---游标

    --查询所有员工的员工号.姓名和职位的信息.DECLARE --定义游标 CURSOR emp_cursor IS SELECT empno,ename,job FROM emp; v_empno e ...

  7. synchronized与ReentrantLock实现共享资源的消费

    主方法 public class synchronizedTest { public static void main(String[] args) { long startTime = System ...

  8. Bzoj3517 翻硬币题解 解异或方程组

    3517: 翻硬币 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 281  Solved: 211[Submit][Status][Discuss] D ...

  9. 9.22考试 crf的数数 题解

    这道题当时第一反应是线段树,但没有继续想,因为当时打完第一题打算这道题和第二道题并列做,打完第二道题状压后时间还有两个小时多,先打完暴力再说,打完之后又接着去想,然后想了5分多钟吧,扑街. 然后就发现 ...

  10. android_MultiAutoCompleteTextView

    package cn.com.sxp;import android.app.Activity;import android.os.Bundle;import android.view.View;imp ...