一、硬件与效率的一致性

  计算机的存储设备与处理器的运算速度存在几个数量级的差距,现在计算机系统不得不在内存和处理器之间增加一层高速缓存(cache)来作为缓冲。将运算需要的数据复制到缓存中,让运算能够快速进行,当运算结束的时候再讲数据从缓存同步到内存中,这样处理器无须等待缓慢的内存读写。除了增加高速缓存外,为了使处理器的内存的运算单元能被充分的利用,处理器可能对输入的代码进行乱序执行优化,即常说的重排序,计算后对乱序执行的结果重组,保证结果与顺序执行代码的结果一致,但是并不保证各个语句的计算顺序与代码顺序一致。

  基于高速缓存的存储交互很好的解决了处理器与内存的速度矛盾,引进了一个新的问题:缓存一致性。在多处理器计算机系统中,每个处理器都有自己的高速缓存,而它们又共享同一主内存,当处理器的运算任务涉及到同一块主内存区域的时候,很可能导致各自的缓存数据不一致。解决这个问题,需要各个处理器访问缓存的时候遵循一些协议,在读写时根据协议来进行操作。

二、java内存模型

  内存模型可以理解为在特定的操作协议下,对特定的内存或高速缓存进行读写访问的过程抽象,不同架构的物理机器可以拥有不一样的内存模型,而java虚拟机有自己的内存模型。同样的,java虚拟机的即时编译器中有类似的指令重排序优化功能。java虚拟机规范中定义的内存模型用来屏蔽掉各种硬件环境和操作系统的内存访问差异,以实现让java程序在各个平台都能达到一致的内存访问效果。在jdk1.5发布后,java的内存模型已经成熟和完善起来。

  java内存模型的主要目标是为了定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和从内存中取出变量的底层细节。这里的变量与java语言中说的变量不是同一个东西,包括:实例字段,静态变量和构成数组对象的元素,但是不包括局部变量和方法参数(线程私有,不会共享,自然不存竞争问题)。java内存模型不限制执行引擎使用处理器的寄存器或缓存来和主内存进行交互,不限制即时编译器进行重排序优化。java内存模型的规范如下:

1.主内存与工作内存

Java内存模型规定
.所有的变量都存储在主内存(虚拟机内存的一部分)。
.每条线程有自己的工作内存,线程的工作内存保存了被该线程使用到的变量的主内存副本拷贝,线程对变量的读取,赋值等必须在工作内存中进行。
.不同线程之间无法直接访问对方工作内存中的变量,线程间的变量值传递需要借助主内存完成。

2.java内存间的交互操作

内存交互:即一个变量如何从主内存拷贝到工作内存,又如何从工作内存同步到主内存之类的实现细节。Java内存模型定义八种操作来完成,并且下面八种操作都是原子的,不可再分的。如下:

lock(锁定):作用于主内存中的变量,它把变量标识为一条线程独占的状态。

unlock(解锁):作用主内存中的变量,它把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定。

read(读取):作用于主内存中的变量,把一个变量从主内存传输到线程的工作内存中,以便随后的load操作。

load(载入):作用于工作内存中的变量,把read操作从主内存中得到的变量放入工作内存的变量副本中。

use(使用):作用于工作内存的变量,把一个工作内存中的变量的值传递给执行引擎,每当虚拟机遇到一个需要使用到变量的值得字节码指令的时候将会执行这个操作。

assign(赋值):作用工作内存的变量,把从执行引擎接收到的值付赋给工作内存中的变量。

store(存储):作用于工作内存中的变量,把工作内存中的一个变量的值传递到主内存中,以便后续的write操作。

write(写入):作用于主内存中的变量,把store操作得到的变量的写入到主内存中对应的变量中。

注意:java内存模型要求read和load操作顺序执行,同时要求store和write操作顺序执行。

3.volatile变量的特殊规则

  • 保证volatile变量对所有线程的可见性,与普通变量的区别保证变量的新值能立即同步到主内存,以及每次使用的时候立即从主内存刷新。
  • volatile变量禁止指令重排序优化(主要通过内存屏障指令来实现)

内存屏障:指重排序的时候,不能把后面的指令重排序到内存屏障之前的位置。

4.long和doubel型变量的特殊规则

允许虚拟机将没被volatile修饰的64位数据的读写划分为两次32位的操作来进行。如long和double变量。但是目前商用虚拟机几乎把64数据的读写操作作为原子操作来对待。

5.原子性、可见性和有序性

原子性:即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。原子代表不可分割性。基本数据类型的访问读写具备原子性。synchronized块之间的操作具备原子性。

可见性:当一个线程修改共享变量的值,其他线程能够立即知道这个修改。java中volatile,synchronized和final能够实现变量的可见性。

有序性:线程内表现为串行语义,指令重排序和工作内存与主内存同步延迟的现象导致在其他线程观察另外一个线程,其操作都是无序的。java提供volatile和synchronized两个关键字来保证线程之间操作的有序性。

5.先行发生原则

java语言中有一个先行发生的原则,即happen-before,是判断是否存在竞争和线程是否安全的主要依据。java内存模型规定天然先行发生关系:

  • 程序次序规则:一个线程内,按照代码顺序,书写在前面的操作先行发生于书写在后面的操作;
  • 锁定规则:一个unLock操作先行发生于后面对同一个锁额lock操作;
  • volatile变量规则:对一个变量的写操作先行发生于后面对这个变量的读操作;
  • 线程启动规则:Thread对象的start()方法先行发生于此线程的每个一个动作;
  • 线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生;
  • 线程终结规则:线程中所有的操作都先行发生于线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值手段检测到线程已经终止执行;
  • 对象终结规则:一个对象的初始化完成先行发生于他的finalize()方法的开始;
  • 传递规则:如果操作A先行发生于操作B,而操作B又先行发生于操作C,则可以得出操作A先行发生于操作C;

三、java线程在虚拟机中的实现

  线程是比进程更轻量级的调度执行单位,线程的引入,可以把一个进程的资源分配和调度分开,各个线程可以共享进程资源,又可以独立调度(线程是CPU调度的基本单位)。主流的操作系统都提供了线程实现,Java语言则提供在不同硬件和操作系统平台下对线程的统一处理。每个执行了start()且还未结束的java.lang.Thread类的实例就代表一个线程。

1.Java线程的实现

Java线程模型在jdk1.2后是基于操作系统原生线程模型来实现的,因此操作系统支持怎样的线程模型,在很大程度上决定了Java虚拟机的线程是怎样映射的。对于sun JDK来说,它在windows和linux都是使用一对一的线程模型实现,即一条java线程映射到一条轻量级进程之中。

2.Java线程调度

线程调度:系统为线程分配处理器使用权的过程。主要两种方式:协同式线程调度和抢占式线程调度。java线程调度取决于操作系统的线程调度模式。

3.线程状态转换

java语言定义五种线程状态,任意一个时间点,一个线程只能有且只有其中一种状态,五种状态如下:

. 新建状态(New)         : 线程对象被创建后,就进入了新建状态。例如,Thread thread = new Thread()。
. 就绪状态(Runnable): 也被称为“可执行状态”。线程对象被创建后,其它线程调用了该对象的start()方法,从而来启动该线程。例如,thread.start()。处于就绪状态的线程,随时可能被CPU调度执行。
. 运行状态(Running) : 线程获取CPU权限进行执行。需要注意的是,线程只能从就绪状态进入到运行状态。
. 阻塞状态(Blocked) : 阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
() 等待阻塞 -- 通过调用线程的wait()方法,让线程等待某工作的完成。
() 同步阻塞 -- 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态。
() 其他阻塞 -- 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
. 结束状态(Terminated): 线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

线程状态转换关系如下:

JVM--内存模型与线程的更多相关文章

  1. 漫谈 JVM —— 内存模型、线程、锁

    Java 内存模型(JMM),实际上的目的就是为了统一内存管理.这让我想到了,作为一个程序员总是想着有银弹,有一个代码能万能的在所有场景上.经过多次尝试我发现这是不可能的:需求在变,技术在更新,没有什 ...

  2. 从linux进程角度看JVM内存模型

    普通进程栈区,在JVM一般仅仅用做线程栈,如下图所示 首先是永久代.永久代本质上是Java程序的代码区和数据区.Java程序中类(class),会被加载到整个区域的不同数据结构中去,包括常量池.域.方 ...

  3. jvm(12)-java内存模型与线程

    [0]README 0.1)本文部分文字描述转自“深入理解jvm”,旨在学习“java内存模型与线程” 的基础知识:   [1]概述 1)并发处理的广泛应用是使得 Amdahl 定律代替摩尔定律称为计 ...

  4. JVM内存模型、指令重排、内存屏障概念解析

    在高并发模型中,无是面对物理机SMP系统模型,还是面对像JVM的虚拟机多线程并发内存模型,指令重排(编译器.运行时)和内存屏障都是非常重要的概念,因此,搞清楚这些概念和原理很重要.否则,你很难搞清楚哪 ...

  5. JVM内存模型和性能优化 转

    JVM内存模型和性能优化 JVM内存模型优点 内置基于内存的并发模型:      多线程机制 同步锁Synchronization 大量线程安全型库包支持 基于内存的并发机制,粒度灵活控制,灵活度高于 ...

  6. JVM内存模型和性能优化

    JVM内存模型优点 内置基于内存的并发模型:      多线程机制 同步锁Synchronization 大量线程安全型库包支持 基于内存的并发机制,粒度灵活控制,灵活度高于数据库锁. 多核并行计算模 ...

  7. JVM初探 -JVM内存模型

    JVM初探 -JVM内存模型 标签 : JVM JVM是每个Java开发每天都会接触到的东西, 其相关知识也应该是每个人都要深入了解的. 但接触了很多人发现: 或了解片面或知识体系陈旧. 因此最近抽时 ...

  8. JVM内存模型和关键参数设置

    一. JVM内存模型: Jvm内存模型是学好Java很重要的一部分,该部分学习能让我们在系统运维的时候,或者优化服务器的时候能够有方法,懂原理. 二. Jvm关键参数: 1. 堆大小设置参数: -Xm ...

  9. 记录JVM内存模型,参数含义和优化

    一.JVM内存模型 (图片来自网络) 根据Java虚拟机规范,JVM将内存划分为: New(年轻代) Tenured(年老代) Perm (永久代) 其中New和Tenured属于堆内存,堆内存会从J ...

  10. jvm内存模型和内存分配

    1.什么是jvm? (1)jvm是一种用于计算设备的规范,它是一个虚构出来的机器,是通过在实际的计算机上仿真模拟各种功能实现的. (2)jvm包含一套字节码指令集,一组寄存器,一个栈,一个垃圾回收堆和 ...

随机推荐

  1. 解决最新版 mac os sierra usb网卡不能使用的问题

    解决最新版 mac os sierra usb网卡不能使用的问题 解决最新版 mac os sierra usb网卡不能使用 无法使用未签名第三驱动的问题 我的情况是 mac os sierra 使用 ...

  2. github常见操作和常见错误

    配置git的时候会使用git config,三种配置分别为git config.git config --global.git config --system. 它们之前的优先级为(由高到低):git ...

  3. 集群、RAC和MAA

    集群:是一种由两台或多台节点机构成的松散耦合的计算节点集合,这个集合在整个网络中表现为单一的系统,并通过单一接口进行使用和管理.给用户提供网络服务或应用程序的单一视图.大多数模式下,集群中所有计算机都 ...

  4. Mint-UI 的 DatetimePicker 日期时间插件的安装与使用

    简介:Mint-UI是饿了么出品的基于vue的移动端组件库(element-ui是桌面端) 官网:http://mint-ui.github.io/docs/#/zh-cn2 项目环境:vue-cli ...

  5. vue-知乎日志

    1.项目API来源 2.项目地址 3.截图                                                       4.功能 首页 轮播图 动态消息 下拉刷新 动态 ...

  6. 7. CSS装饰网页的样式

    CSS中有哪些用来装饰网页的样式呢?在这里我们对一些常用的样式做了总结. 字体样式 /* * 一般样式书写 */ .font_style_1{ font-family: "华文行楷" ...

  7. Android编译命令

    目录 说在前面 编译流程 编译指令 代码编译 代码检索 其他指令 说在前面 从最开始接触Android系统开始,每次进行代码编译都需要网上搜索编译指令.后来大致熟悉了Android的编译体系,加深了对 ...

  8. Django之图书管理系统

    出版社的增删改查 展示出版社列表: 1. 创建一个表结构:   2. 再配合那俩条命令即可创建一个press表 创建出版社函数,并在url中进行配置 创建HTML页面,展示出版社的表 for循环 {% ...

  9. vue实现图片路径传送

    <!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"& ...

  10. 常见java异常英语词汇(一)

    denied   /dɪ'naɪəd/    adj 拒签  v 拒绝