深入理解Java虚拟机8-chap12-13-斗者5星
一、操作系统与内存
- 通过在处理器与内存之间添加一层访问及更新速度更快的高速缓存,可以一定程度解决处理器与内存速度的矛盾
- 引入新问题:缓存一致性,即每个处理器只与自己的缓存交互,如果操作的是内存中的同一块内存,会出现数据不一致的现象
二、Java内存模型
1.Java内存模型的主要目的:定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和从内存中取出变量这样的底层细节。
2.变量包括:实例字段、静态字段和构成数组对象的元素,不包括局部变量和方法参数,因为这是线程私有的,不会存在竞争问题。
3.Java线程、工作内存与主线程之间的交互关系
- 工作内存中存放了变量的主内存副本拷贝,线程对变量的操作必须在工作内存中进行,线程间变量值传递均需要通过主内存
- 主内存对应Java堆中对象实例数据部分,工作内存对应虚拟机栈的部分区域
4.内存间的交互操作,均是原子操作,不可再分(double与long类型除外)
- lock(锁定):作用于主内存变量,它把一个变量标识为一条线程独占的状态。
- unlock(解锁):作用于主内存变量,它把一个处理锁定的状态的变量释放出来,释放后的变量才可以被其它线程锁定,unlock之前必须将变量值同步回主内存。
- read(读取):作用于主内存变量,它把一个变量的值从主内存传输到线程的工作内存中,以便随后的load动作使用。
- load(载入):作用于工作内存变量,它把read操作从主内存中得到的值放入工作内存的变量副本中。
- use(使用):作用于工作内存中的变量,它把工作内存中一个变量的值传递给执行引擎,每当虚拟机遇到一个需要使用到变量的字节码指令时将会执行这个操作。
- assign(赋值):作用于工作内存变量,它把一个从执行引擎接到的值赋值给工作内存的变量,每当虚拟机遇到一个给变量赋值的字节码指令时执行这个操作。
- store(存储):作用于工作内存的变量,它把工作内存中一个变量的值传送到主内存中,以便随后的write操作使用。
- write(写入):作用于主内存的变量,它把store操作从工作内存中得到的值放入主内存的变量中。
5.操作连续性保证,没有保证连续执行
- 如果要把一个变量从主内存复制到工作内存,那就要顺序地执行read和load操作
- 如果要把变量从工作内存同步回主内存,就要顺序地执行store和write操作
6.执行上述8条基础操作时必须满足一下规则(部分):
- 不允许read和load、store和write操作之一单独出现,即不允许一个变量从主内存读取了但工作内存不接受,或者从工作内存发起回写但主内存不接受的情况出现。
- 不允许一个线程丢弃它的最近的assign操作,即变量在工作内存中改变(为工作内存变量赋值)了之后必须把该变化同步回主内存。
- 一个新变量只能在主内存中“诞生”,不允许在工作内存中直接使用一个未被初始化(load和assign)的变量,换话说就是一个变量在实施use和store操作之前,必须先执行过了assign和load操作。
- 如果一个变量事先没有被load操作锁定,则不允许对它执行unlock操作:也不允许去unlock一个被其它线程锁定的变量。
- 对一个变量执行unloack之前,必须把此变量同步回主内存中(执行store和write操作)
7.volatile变量:最轻量级的同步机制
1)定义volatile变量后,保证了两个特性
- 保证变量对所有线程的可见性,指当一个线程修改了变量的值,新值对于其他线程是立即可知的,当然需要通过主存来传递
a.不代表并发下是安全的,因为Java里的运算并非原子操作,里类变量race++,反编译后是4条字节码指令如下,当getstatic把race的值取到操作栈顶时,volatile关键字保证了race的值在此时是正确的,但是在执行iconst_1、iadd时,race的值可能已经改变,所以栈顶的数据过期了,造成结果错误.
b.volatile变量只保证可见性,当可能存在多线程竞争,需要通过加锁保证原子性
- 禁止指令重排序优化:保证变量赋值操作与程序代码中的执行顺序一致,普通变量只保证赋值动作正确,不保证顺序
a.实现原理:添加内存屏障,重排序不能把后面的指令重排序到内存屏障前
2)volatile变量性能
- 读操作与普通变量几乎没什么差别
- 写操作可能慢一点,因为需要添加内存屏障来保证处理器不发生乱序执行,但仍然比锁低。
3)volatile与锁的选择:volatile是否能满足使用场景需求
8.Java内存模型特征
- 原子性:基本数据访问read、load等读写具备原子性,更大场景通过lock、unlock,或者synchronized,同步块之间的操作也保证原子性
- 可见性:指当一个线程修改了共享变量的值,其他线程能够立即得知这个修改,volatile、synchronized、final等关键字
- 有序性:如果在本线程内观察,所有操作都是有序的;如果在一个线程中观察另一个线程,所有操作都是无序的。前半句是指“线程内表现为串行语义”,后半句是指“指令重排序”现象和“工作内存主主内存同步延迟”现象。
9.先行发生原则:操作A先于操作B,则A产生的影响能被B观察到,影响包括修改了内存中共享变量的值、发送了消息、调用了方法
- 程序次序规则(Pragram Order Rule):在一个线程内,按照程序代码顺序,书写在前面的操作先行发生于书写在后面的操作。准确地说应该是控制流顺序而不是程序代码顺序,因为要考虑分支、循环结构。
- 管程锁定规则(Monitor Lock Rule):一个unlock操作先行发生于后面对同一个锁的lock操作。这里必须强调的是同一个锁,而”后面“是指时间上的先后顺序。
- volatile变量规则(Volatile Variable Rule):对一个volatile变量的写操作先行发生于后面对这个变量的读取操作,这里的”后面“同样指时间上的先后顺序。
- 线程启动规则(Thread Start Rule):Thread对象的start()方法先行发生于此线程的每一个动作。
- 线程终止规则(Thread Termination Rule):线程中的所有操作都先行发生于对此线程的终止检测,我们可以通过Thread.join()方法结束,Thread.isAlive()的返回值等作段检测到线程已经终止执行。
- 线程中断规则(Thread Interruption Rule):对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生,可以通过Thread.interrupted()方法检测是否有中断发生。
- 对象终结规则(Finalizer Rule):一个对象初始化完成(构造方法执行完成)先行发生于它的finalize()方法的开始。
- 传递性(Transitivity):如果操作A先行发生于操作B,操作B先行发生于操作C,那就可以得出操作A先行发生于操作C的结论。
结论:时间上先发生不地标操作会是先发生,因为会有指令重排序,但是指令重排序不会违背先行发生原则。
三、线程
1.线程实现的3种方式
- 内核线程实现:需要在用户态与内核态切换,代价较高
- 用户线程实现:需要考虑创建、切换、调度等各种问题
- 用户线程加轻量级进程混合实现:Java采用的模式,抢占式调度,操作系统提供支持的轻量级进程作为用户线程和内核线程的桥梁
2.状态转换
四、线程安全
1.定义:当多个线程访问一个对象时,如果不用考虑这些线程在运行环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,那么这个对象时线程安全的。
2.Java语言中的线程安全
- 不可变:一定线程安全,通常是把对象中带有状态的变量声明为final,如String、Number的部分子类、BigInteger等(不包括AtomicInteger)
- 绝对线程安全:Java API声明自己为线程安全的类,大多数都不是绝对线程安全,需要在使用时进行同步
- 相对线程安全:如容器类等
- 线程兼容:对象本身不是线程安全的,但是在调用段正确使用同步手段可以在并发环境下安全使用
- 线程对立:无论调用端是否采用同步措施,都无法在并发环境下正确使用,较少。
3.线程安全的实现方法
1)互斥同步:临界区、互斥量、信号量等,Java中最基本的同步手段是synchronized,经过编译在同步块前后形成加解锁指令,如果指明对象参数,则锁定对象引用,否则锁定对象实例
a.synchronized两层语义:
- synchronized同步块对于同一条线程是可重入的
- 同步块在已进入的线程执行完,会阻塞后面其他线程的进入
b.由于synchronized会带来线程阻塞和唤醒等用户态与内核态切换的动作,耗费处理器时间,所以是一个重量级操作,可以通过自旋优化
c.java.util.concurrent中的重入锁
- 用法与synchronized类似
- 添加了高级功能:等待可中断、可实现公平锁、锁绑定多个条件
- synchronized经过优化,性能基本与重入锁持平,虚拟机未来性能改进肯定偏向原生的synchronized
2)非阻塞同步:互斥同步是悲观的并发策略,认为只要不去做正确的同步措施,就一定出问题
- 可以选择基于冲突检测的乐观并发策略(先进行操作,如果没有其他线程争用数据,则操作成功,如果有争用,则失败,采用其他补救(如不断重试,直到成功)),不需要挂起线程,所以称为非阻塞同步
- 依赖指令集:需要操作和冲突检测者两个步骤具备原子性,如CAS(很多Atomic操作)(比较并交换cas(v,a,b),如果v内存内容=a,则在v中填入b),CAS存在ABA问题
3)无同步方案:本来不涉及共享数据
- 可重入代码:可重入一定线程安全,反之不是,特征:不依赖存储在堆上的数据和公用的系统资源等,判断原则:返回结果可预测
- 线程本地存储:web中一个请求对应一个服务器线程,都会使用线程本地存储来解决线程安全问题
五、锁优化
1.自旋锁与自适应自旋
2.锁消除
3.锁粗化
4.轻量级锁
5.偏向锁
深入理解Java虚拟机8-chap12-13-斗者5星的更多相关文章
- 《深入理解Java虚拟机》-----第13章 线程安全与锁优化
概述 在软件业发展的初期,程序编写都是以算法为核心的,程序员会把数据和过程分别作为独立的部分来考虑,数据代表问题空间中的客体,程序代码则用于处理这些数据,这种思维方式直接站在计算机的角度去抽象问题和解 ...
- 深入理解java虚拟机-第13章-线程安全与锁优化
第十三章 线程安全与锁优化 线程安全 java语言中的线程安全 1 不可变.Immutable 的对象一定是线程安全的 2 绝对线程安全 一个类要达到不管运行时环境如何,调用者都不需要额外的同步措施, ...
- 《深入理解Java虚拟机》虚拟机性能监控与故障处理工具
上节学习回顾 从课本章节划分,<垃圾收集器>和<内存分配策略>这两篇随笔同属一章节,主要是从理论+实验的手段来讲解JVM的内存处理机制.好让我们对JVM运行机制有一个良好的概念 ...
- 深入理解java虚拟机(5)---字节码执行引擎
字节码是什么东西? 以下是百度的解释: 字节码(Byte-code)是一种包含执行程序.由一序列 op 代码/数据对组成的二进制文件.字节码是一种中间码,它比机器码更抽象. 它经常被看作是包含一个执行 ...
- 深入理解java虚拟机(4)---类加载机制
类加载的过程包括: 加载class到内存,数据校验,转换和解析,初始化,使用using和卸载unloading过程. 除了解析阶段,其他过程的顺序是固定的.解析可以放在初始化之后,目的就是为了支持动态 ...
- 深入理解Java虚拟机--下
深入理解Java虚拟机--下 参考:https://www.zybuluo.com/jewes/note/57352 第10章 早期(编译期)优化 10.1 概述 Java语言的"编译期&q ...
- 深入理解Java虚拟机--中
深入理解Java虚拟机--中 第6章 类文件结构 6.2 无关性的基石 无关性的基石:有许多可以运行在各种不同平台上的虚拟机,这些虚拟机都可以载入和执行同一种平台无关的字节码(ByteCode),从而 ...
- 《深入理解Java虚拟机:JVM高级特性与最佳实践》【PDF】下载
<深入理解Java虚拟机:JVM高级特性与最佳实践>[PDF]下载链接: https://u253469.pipipan.com/fs/253469-230062566 内容简介 作为一位 ...
- jvm--深入理解java虚拟机 精华总结(面试)(转)
深入理解java虚拟机 精华总结(面试)(转) 原文地址:http://www.cnblogs.com/prayers/p/5515245.html 一.运行时数据区域 3 1.1 程序计数器 3 1 ...
- 《深入理解java虚拟机》笔记
二.java内存区域与内存溢出异常 0.在内存管理领域,java与c/c++不同的是,在java虚拟机自动内存管理机制下,java不需要手动去为对象写配对的free内存的代码,不容易出现内存泄漏和内存 ...
随机推荐
- Java线程池ExecutorService 代码备忘
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5)创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待 p ...
- spring的xml配置声明以及相应的问题处理
spring的xml配置声明: xml配置声明 Code 问题处理 问题1 xml报错: cvc-elt.1: Cannot find the declaration of element 'bea ...
- 多媒体开发(6):滤镜实现各种图片效果 | Video-Filters | avfilter | 变色
之前讲过使用FFmpeg的drawtext滤镜(把图片或文字加到视频上),而实际上,FFmpeg的滤镜很强大,远不止加字幕或加图片的功能.滤镜是很有趣的,可以把图片变模糊.变色.缩放旋转,等等. 本文 ...
- [wordpress]WordPress地址(URL)错误,修改解决方案
本人在修改Wordpress地址(URL)时,误操作使URL指向错误,后台无法进入. 解决方案 1.先利用Putty登陆到自己的服务器上(这里登陆方法我不再赘述): 2.登陆MySqL,并输入密码: ...
- 【java】-- java并发包总结
1.同步容器类 1.1.Vector与ArrayList异同 1.Arraylist和Vector都是采用数组方式存储数据,都允许直接序号索引元素,所以查找速度快,但是插入数据等操作涉及到数组元素移动 ...
- 如何设计一个restful风格的API
1.API接口应该尽量兼容之前的版本,在URL上应保留版本号,并同时兼容多个版本 2.每一个URI代表一个资源 3.请求方式要与http请求方式一致,GET(获取),POST(新增),PUT(更新全部 ...
- 爬虫——scrapy入门
scrapy 安装scrapy pip install scrapy windows可能安装失败,需要先安装c++库或twisted,pip install twisted 创建项目 scrapy s ...
- SVN-您的主机中的软件中止了一个已建立的连接
关于这个问题,网络上有各种解决的办法,关闭防火墙,HTTP/HTTPS切换,改端口... ...但我都试了没有用.本来一直用的好好的,突然就出现了这个问题,而且在几分钟前都是正常的.下面来说说我都干了 ...
- 关于Android studio 设置点击打不开的解决
今天早上觉得字体太小了想改下字体发现设置点不开,后来发现是打了汉化包的bug,后来换了一个汉化包就能打开了.
- __x__(7)0905第二天__HTML的发展
HTML的发展 浏览器各个厂商有不同的标准,一个网页的兼容性非常差. 于是,W3C出来了,作为公益组织定义了HTML标准. 在 1993.6 实现并发布了第一个 HTML. 在 1995.11 开始创 ...