文章目录

  • 一、原子性
    • 如何保证原子性?
      • 1、使用原子类来保证线程安全
      • 2、使用synchronized 互斥锁
  • 二、可见性
    • 如何保证可见性?
  • 三、有序性
    • 如何保证有序性?
      • 1、volatile关键字
      • 2、synchronized关键字

一、原子性

Java 内存模型保证了 read、load、use、assign、store、write、lock 和 unlock 操作具有原子性,例如对一个 int 类型的变量执行 assign 赋值操作,这个操作就是原子性的。但是 Java 内存模型允许虚拟机将没有被 volatile 修饰的 64 位数据(long,double)的读写操作划分为两次 32 位的操作来进行,即 load、store、read 和 write 操作可以不具备原子性。

有一个错误认识就是,int 等原子性的类型在多线程环境中不会出现线程安全问题。前面的线程不安全示例代码中,cnt 属于 int 类型变量,1000 个线程对它进行自增操作之后,得到的值为 997 而不是 1000。

为了方便讨论,将内存间的交互操作简化为 3 个:load、assign、store。

下图演示了两个线程同时对 cnt 进行操作,load、assign、store 这一系列操作整体上看不具备原子性,那么在 T1 修改 cnt 并且还没有将修改后的值写入主内存,T2 依然可以读入旧值。可以看出,这两个线程虽然执行了两次自增运算,但是主内存中 cnt 的值最后为 1 而不是 2。因此对 int 类型读写操作满足原子性只是说明 load、assign、store 这些单个操作具备原子性。

如何保证原子性?

1、使用原子类来保证线程安全

原子类位于 java.util.concurrent.atmoic 包,这里以AtomicInteger类为例:
AtomicInteger 能保证多个线程修改的原子性。

使用 AtomicInteger 重写之前线程不安全的代码之后得到以下线程安全实现:

public class AtomicExample {private AtomicInteger cnt = new AtomicInteger();public void add() {cnt.incrementAndGet();}public int get() {return cnt.get();}
}
public static void main(String[] args) throws InterruptedException {final int threadSize = 1000;AtomicExample example = new AtomicExample(); // 只修改这条语句final CountDownLatch countDownLatch = new CountDownLatch(threadSize);ExecutorService executorService = Executors.newCachedThreadPool();for (int i = 0; i < threadSize; i++) {executorService.execute(() -> {example.add();countDownLatch.countDown();});}countDownLatch.await();executorService.shutdown();System.out.println(example.get());
}

输出

1000

2、使用synchronized 互斥锁

它对应的内存间交互操作为:lock 和 unlock,在虚拟机实现上对应的字节码指令为 monitorenter 和 monitorexit。

public class AtomicSynchronizedExample {private int cnt = 0;public synchronized void add() {cnt++;}public synchronized int get() {return cnt;}
}
public static void main(String[] args) throws InterruptedException {final int threadSize = 1000;AtomicSynchronizedExample example = new AtomicSynchronizedExample();final CountDownLatch countDownLatch = new CountDownLatch(threadSize);ExecutorService executorService = Executors.newCachedThreadPool();for (int i = 0; i < threadSize; i++) {executorService.execute(() -> {example.add();countDownLatch.countDown();});}countDownLatch.await();executorService.shutdown();System.out.println(example.get());
}

输出

1000

二、可见性

可见性指当一个线程修改了共享变量的值,其它线程能够立即得知这个修改。Java 内存模型是通过在变量修改后将新值同步回主内存,在变量读取前从主内存刷新变量值来实现可见性的。

如何保证可见性?

  • volatile
  • synchronized,对一个变量执行 unlock 操作之前,必须把变量值同步回主内存。
  • final,被 final 关键字修饰的字段在构造器中一旦初始化完成,并且没有发生 this 逃逸(其它线程通过 this 引用访问到初始化了一半的对象),那么其它线程就能看见 final 字段的值。

对前面的线程不安全示例中的 cnt 变量使用 volatile 修饰,不能解决线程不安全问题,因为 volatile 并不能保证操作的原子性。

三、有序性

有序性是指:在本线程内观察,所有操作都是有序的。在一个线程观察另一个线程,所有操作都是无序的,无序是因为发生了指令重排序。在 Java 内存模型中,允许编译器和处理器对指令进行重排序,重排序过程不会影响到单线程程序的执行,却会影响到多线程并发执行的正确性。

如何保证有序性?

1、volatile关键字

volatile 关键字通过添加内存屏障的方式来禁止指令重排,即重排序时不能把后面的指令放到内存屏障之前。

2、synchronized关键字

也可以通过 synchronized 来保证有序性,它保证每个时刻只有一个线程执行同步代码,相当于是让线程顺序执行同步代码。

Java内存模型三大特性相关推荐

  1. Java内存模型及三大特性

    在了解Java的内存模型之前先了解下计算机处理并发的模型处理: 由于计算的处理器的处理速度与存储设备的读写速度的差异较大,所以加入一层读写接近处理器运算速度的高速缓存(Cache)来作为内存与处理器之 ...

  2. Java并发知识梳理(上):并发优缺点,线程状态转换,Java内存模型,Synchronized,Volatile,final,并发三特性,Lock与AQS,ReetrandLock

    努力的意义,就是,在以后的日子里,放眼望去全是自己喜欢的人和事! 整个系列文章为Java并发专题,一是自己的兴趣,二是,这部分在实际理解上很有难度,另外在面试过程中也是经常被问到.所以在学习过程中,记 ...

  3. java(线程特性,Volatile作用,java内存模型)

    1.java线程特性   1.原子性:即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行 银行转账,自己转100给别人,自己账户少100 别人多100 不会出现,自己 ...

  4. 并发编程专题——第一章(深入理解java内存模型)

    说到并发编程,其实有时候觉得,开发中真遇到这些所谓的并发编程,场景多吗,这应该是很多互联网的在职人员,一直在考虑的事情,也一直很想问,但是又不敢问,想学习的同时,网上这些讲的又是乱七八糟,那么本章开始 ...

  5. 并发编程之Java内存模型

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

  6. Java多线程编程笔记4:Java内存模型

    Java内存模型 Java内存模型试图屏蔽各种硬件和操作系统的内存访问差异,以实现让Java程序在各种平台下都能达到一致的内存访问效果. 处理器上的寄存器读写速度比内存快几个数量级,为了解决这种速度矛 ...

  7. java内存模型按照线程隔离性_深入理解Java多线程与并发框(第③篇)——Java内存模型与原子性、可见性、有序性...

    一.Java内存模型 Java Memory Modle,简称 JMM,中文名称 Java内存模型,它是一个抽象的概念,用来描述或者规范访问内存变量的方式.因为各中计算机的操作系统和硬件不同,方式机制 ...

  8. JAVA 内存模型 (Java Memory Model,JMM)

    JAVA内存模型 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家.点击跳转到教程. Java内存模型(Java Memory Model,JMM) 是在硬件内存模型基 ...

  9. JAVA内存模型与线程安全

    什么是线程安全?在<<深入理解Java虚拟机>>中看到的定义.原文如下:当多个线程访问同一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替运行,也不需要进行额外的同步, ...

最新文章

  1. LAMP服务搭建详解
  2. echo -e 参数
  3. bootstrap的滚动监听
  4. 2019-11-08 频域的直观感受
  5. php把数字倒着展示,jQuery+PHP实现动态数字展示特效
  6. java api es_ES 常用java api
  7. 2016年安防企业如何因势而动 顺势而为
  8. [jquery] 图片热区随图片大小自由缩放
  9. C#——NotifyICON的使用
  10. 国内智能工厂建设现状以及未来发展趋势介绍
  11. html的vr图怎么制作,什么叫vr全景展示?vr图片怎么做的?
  12. 广州图书馆——携程评论爬取
  13. 惠普刀片服务器型号,HP ProLiant刀片服务器简介
  14. Facade与Adapter模式应用
  15. 结构化思维模型的构建(多种思维参考)
  16. python||报错‘gbk‘ codec can‘t decode byte 0x80 in position 8: illegal multibyte sequence
  17. 极验验证的滑动验证码破解
  18. 中电药明招募资深Python开发工程师
  19. 锁系列:一、悲观 / 乐观锁原理与运用
  20. python会搞坏电脑吗_Python 操作几个坏习惯,你中了吗?

热门文章

  1. Python 的PIL,可以解决ImportError The _imagingft C module is not installed
  2. 【BZOJ】【3301】【USACO2011 Feb】Cow Line
  3. 向窗口发送ctrl c复制 消息
  4. C# 特性(Attribute)学习
  5. Symbian c++ 在3版中实现并动态配置开机自启动
  6. 《设计模式详解》行为型模式 - 解释器模式
  7. Linux系统管理(8)——Ubuntu安装ssh服务 以及版本查看命令
  8. DBSCAN聚类算法初探(五)
  9. 谁说数据分析很难?看完这7大分析套路后,还学不会的来找我
  10. 数据可视化必备的高逼格图表特效,学会只需要五分钟