内存模型

深入理解Java内存模型(四)——volatile

陌路散爱 提交于 2020-03-12 17:05:20
作者 程晓明 发布于 2013年2月5日 领域 架构 & 设计 , 语言 & 开发 主题 Java , 多线程 , 并发 , 内存模型 , 专栏 volatile的特性 当我们声明共享变量为volatile后,对这个变量的读/写将会很特别。理解volatile特性的一个好方法是:把对volatile变量的单个读/写,看成是使用同一个监视器锁对这些单个读/写操作做了同步。下面我们通过具体的示例来说明,请看下面的示例代码: class VolatileFeaturesExample { volatile long vl = 0L; //使用volatile声明64位的long型变量 public void set(long l) { vl = l; //单个volatile变量的写 } public void getAndIncrement () { vl++; //复合(多个)volatile变量的读/写 } public long get() { return vl; //单个volatile变量的读 } } 假设有多个线程分别调用上面程序的三个方法,这个程序在语意上和下面程序等价: class VolatileFeaturesExample { long vl = 0L; // 64位的long型普通变量 public synchronized void set(long l)

JSR133给Java内存模型定义的happen-before规则

依然范特西╮ 提交于 2020-03-11 17:43:38
单线程规则:同一个线程中的每个操作都happens-before于出现在其后的任何一个操作。 对一个监视器的解锁操作happens-before于每一个后续对同一个监视器的加锁操作。 对volatile字段的写入操作happens-before于每一个后续的对同一个volatile字段的读操作。 Thread.start()的调用操作会happens-before于启动线程里面的操作。 一个线程中的所有操作都happens-before于其他线程成功返回在该线程上的join()调用后的所有操作。 一个对象构造函数的结束操作happens-before与该对象的finalizer的开始操作。 传递性规则:如果A操作happens-before于B操作,而B操作happens-before与C操作,那么A动作happens-before于C操作。 实际上这组happens-before规则定义了操作之间的内存可见性,如果A操作happens-before B操作,那么A操作的执行结果(比如对变量的写入)必定在执行B操作时可见。 为了更加深入的了解这些happens-before规则,我们来看一个例子: //线程A,B共同访问的代码 Object lock = new Object(); int a=0; int b=0; int c=0; //线程A,调用如下代码

java中的内存模型

独自空忆成欢 提交于 2020-02-28 16:05:23
概述 在java中应为不同的目的可以将java划分为两种内存模型:gc内存模型。并发内存模型。 gc内存模型 java与c++之间有一堵由内存动态分配与垃圾收集技术所围成的“高墙”。墙外面的人想进去,墙里面的人想出来。 java在执行java程序的过程中会把它管理的内存划分若干个不同功能的数据管理区域。如图: 整体上。分为三部分:栈,堆,程序计数器,他们每一部分有其各自的用途;虚拟机栈保存着每一条线程的执行程序调用堆栈;堆保存着类对象、数组的具体信息;程序计数器保存着每一条线程下一次执行指令位置。这三块区域中栈和程序计数器是线程私有的。也就是说每一个线程拥有其独立的栈和程序计数器。我们可以看看具体结构: 虚拟机/本地方法栈 在栈中,会为每一个线程创建一个栈。线程越多,栈的内存使用越大。对于每一个线程栈。当一个方法在线程中执行的时候,会在线程栈中创建一个栈帧(stack frame),用于存放该方法的上下文(局部变量表、操作数栈、方法返回地址等等)。每一个方法从调用到执行完毕的过程,就是对应着一个栈帧入栈出栈的过程。 本地方法栈与虚拟机栈发挥的作用是类似的,他们之间的区别不过是虚拟机栈为虚拟机执行java(字节码)服务的,而本地方法栈是为虚拟机执行native方法服务的。 方法区/堆 在hotspot的实现中,方法区就是在堆中称为永久代的堆区域。几乎所有的对象/数组的内存空间都在堆上

Java多线程之内存可见性

一曲冷凌霜 提交于 2019-12-06 03:31:30
Java内存模型( JMM ) : 1) 所有的变量都存储在主内存中 2) 每个线程都有自己独立的工作内存, 里面保存该线程使用到的变量的副本 ( 主内存中该变量的一份拷贝 ) JMM 两条规定: 1) 线程对共享变量的所有操作都必须在自己的工作内存中进行 2) 不同线程之间无法直接访问其他线程工作内存中的共享变量, 线程间共享变量值的传递必须通过主内存 线程间共享变量可见性实现的原理: 线程A 对共享变量的修改想被线程B 及时看到, 必须要经过以下2个步骤: 1) 把线程A 工作内存中更新过的共享变量刷新到主内存中 ( store ) 2) 将主内存中最新的共享变量的值共享到线程B 工作内存中 ( load ) Java 语言层面支持的可见性实现方式: 1) synchronized 2) volatile JUC 包下的类也可以实现可见性 1) Atomic 2) ReentrantLock 3) Semaphore 1. synchronized 实现可见性 JMM 关于 synchronized 的两条规定: 1) 线程释放锁前, 必须把共享变量的最新值从该线程的工作内存刷新到主内存中 2) 线程持有锁时, 将清空该线程工作内存中共享变量的值, 从主内存中读取最新的值 synchronized 实现可见性的原因: 线程释放锁前对共享变量的修改在下次持有锁时对其他线程可见