高效并发一 Java内存模型与Java线程(绝对干货)
高效并发一 Java内存模型与Java线程
本篇文章,首先了解虚拟机Java 内存模型的结构及操作,然后讲解原子性,可见性,有序性在 Java 内存模型中的体现,最后介绍先行发生原则的规则和使用.
在多数情况下让计算机同时去做几件事情,不仅是因为计算机的运算能力强大,还有一个重要的原因是计算机的运算速度与它的存储和通信子系统速度的差距太大,大量的时间都花费在磁盘 I/O, 网络通信或者数据库访问上.
1.1 硬件的效率与一致性
计算机的存储设备与处理器运算速度有很大的差距,所以加入了一层高效缓存来作为内存与处理器之间的缓冲:将运算需要的数据复制到缓冲区中,让运算快读进行,当计算完毕之后再将结果从缓冲区同步到内存.但这样做也引入一个新的问题,缓存一致性.
缓存一致性
在多处理系统中,每个处理器都有各自的高效缓存,而它们共享同一内存,当涉及到同一块主内存区域时,将可能导致缓存数据不一致.为了解决一致性的问题,需要各个处理器访问缓存时都遵循一些协议.在读写时根据协议来操作.Java 虚拟机有自己的内存模型,内存模型可以理解为在特定的操作协议下,对特定的内存或高速缓存进行读写访问的抽象过程.
为了使处理器内部单元充分利用,处理器对输入代码进行乱序执行优化,在计算之后将乱序执行的结果重组.保证结果一致.但不保证各个语句计算的先后顺序与输入代码一致.
1.2 Java 内存模型
Java 虚拟机试图定义一种 Java 内存模型来屏蔽各种硬件和操作系统的内存访问差异,实现在各个平台内存访问的一致性.
1.2.1 主内存与工作内存
Java 内存模型主要目标是定义程序中各个变量的访问规则,即虚拟机中从内存中存储和取出变量的底层细节.此处的变量与 Java 编程中的变量有所区别,包括实例字段,静态字段和构成数组对象的元素,但不包括局部变量与方法参数,因为后者是线程私有的,不会被分享.自然就不会存在竞争问题.
Java 内存模型规定所有的变量都存储在主内存中.每条线程还有自己的工作内存,工作内存中保存被该线程使用变量的主内存副本拷贝.线程中所有操作必须在工作内存进行,不能直接读写主内存中的变量,不同线程不能直接访问其它工作内存的变量,线程间的传递需要通过主内存完成.
lock(锁定):作用于主内存变量,将一个变量标识为一条线程独占的状态
unlock(解锁):作用于主内存变量,将处于锁定状态的变量释放出来,释放的变量才可以被其它线程锁定.
read(读取):用作于主内存变量,将一个变量的值从主内存传输到线程的工作内存,以便随后的 load 动作使用
load(载入):用作与工作内存的变量,把 read 操作从主内存中得到的变量值放入工作内存的变量副本中.
use(使用):作用于工作内存的变量,把工作内存中一个变量的值传递给执行引擎.当虚拟机的字节码指令使用到变量的值时将会执行这个操作.
assign(赋值):用作与工作内存的变量,将一个从执行引擎接收到的值赋值给工作内存的变量,当虚拟机的字节码执行遇到一个给变量赋值时执行这个操作.
sore(存储):作用于工作内存变量,将工作内存一个变量值传宋到主内存中,以便随后的 write 操作的使用.
write(写入):用作与主内存的变量,将 store 操作从工作内存中得到的值放入主内存的变量中.
如果要把一个变量从主内存复制到工作内存,就要顺序的执行 read和load 操作.如果要把变量从工作内存同步回主内存,就要顺序执行 store 和 write 操作.
1.2.3 对于 volatile 型变量的特殊规则
关键字 volatile 是 java 虚拟机提供的最轻量级的同步机制,但它并不容易完全被正确,完成地理解.
当一个变量定义为 volatile 之后,将具备两种特性,第一是保证变量对所有线程的可见性,当一个线程修改了这个变量的值,其他线程可以立即得到新值.第二是禁止指令重排序优化,普通的变量仅仅保证方法的执行过程中所有依赖赋值结果的地方都能获取到正确结果,而不能保证变量赋值操作的顺序与程序代码中的执行顺序一致.
1.2.4 原子性,可见性与有序性
原子性
基本数据类型的访问读写是具备原子性的,如果应该场景需要一个更大范围的原子性操作,在 Java 中就是使用 synchronized同步代码块操作也具备原子性.
可见性
可见性指当一个线程修改了共享变量的值,其他线程能够立即得知这个修改.
有序性
Java 内存模型中程序天然有序性可以总结为:在本线程内观察,所有操作都是有序的.如果在一个线程观察另一个线程,所有操作都是无序的.
1.2.4 先行发生原则
先行发生是Java 内存模型中定义的两项操作之间的偏序关系,如果说操作 A 先发生于操作 B ,也就是发生操作B 之前,操作 A 产生的影响能被操作 B 观察到,”影响”包括修改了内存中共享变量的值,发送了消息,调用方法等.
1.3 Java 与线程
1.3.1 线程的实现
线程是比进程更轻量级的调度单位,线程可以把一个进程的资源分配和执行调度分开,各个线程既可以共享进程资源,又可以独立调度.
实现线程主要有3种方式
使用内核线程实现
内核线程是直接由操作系统内核支持的线程,这种线程由内核来完成线程切换,内核通过操纵调度器对线程进行调度,并负责将线程的任务映射到各个处理器上.
1.2.2 内存间交互操作
但是它有局限性,首先由于是基于内核线程实现,所以各种线程操作都需要进行线程调用.而系统调用的代价相对较高,需要在用户态和内核态中来回切换.其次每个轻量级进程都需要一个内核线程支持,因此轻量级进程要消耗一定内核资源,因此一个系统支持轻量级进程的数量是有限的.具有1-5工作经验的,面对目前流行的技术不知从何下手,需要突破技术瓶颈的可以加群。在公司待久了,过得很安逸,但跳槽时面试碰壁。需要在短时间内进修、跳槽拿高薪的可以加群。如果没有工作经验,但基础非常扎实,对java工作机制,常用设计思想,常用java开发框架掌握熟练的可以加群。java架构群:591240817 一起交流。
使用用户线程实现
广义上讲,一个线程只要不是内核线程就可以认为是用户线程
狭义上的用户线程指完全建立在用户空间的线程库上.系统内核不会感知线程存在,用户线程的操作完全在用户态中完成,不需要内核的帮助.
使用用户线程的优势在于不需要系统内核支援,劣势也在于没有系统内核支援所有操作都需要用户进程自己处理.Java,Ruby 等语言曾经使用过用户进程,最终又都放弃.
使用用户线程加轻量级进程混合实现
在这种混合实现下,即存在用户线程,也存在轻量级进程.用户线程还是完全建立在用户空间中,而操作系统提供的轻量级进程则作为用户线程与讷河线程之间的桥梁,这样可以使用内核提供的线程调度功能以及处理器映射.
Java 线程的实现
在 JDK1.2中线程模型替换为基于操作系统原生线程模型来实现.因此操作系统支持怎样的线程模型,很大程度上决定了 Java 虚拟机的线程是怎样映射的.
1.3.2 Java 线程调度
线程调度是指系统为线程分配处理器使用权的过程,主要调度方式有两种:协同式线程调度和抢占式线程调度.
协同式多线程系统,线程的执行时间是由线程本身来控制.当线程工作执行完毕之后,要主动通知系统切换到另一个线程上.缺点是线程时间不可控制,容易造成程序阻塞.
抢占式调度多线程系统,每个线程由系统来分配执行时间,线程的切换不由线程本身来决定,Java 使用抢占式调度.
1.3.3 状态转换
Java 语言定义了5种线程状态,在一个线程点,一个线程只能有且只有一种状态
新建,运行,等待, 阻塞, 结束
高效并发一 Java内存模型与Java线程(绝对干货)的更多相关文章
- 并发研究之Java内存模型(Java Memory Model)
Java内存模型JMM java内存模型定义 上一遍文章我们讲到了CPU缓存一致性以及内存屏障问题.那么Java作为一个跨平台的语言,它的实现要面对不同的底层硬件系统,设计一个中间层模型来屏蔽底层的硬 ...
- 【JVM】JVM内存结构 VS Java内存模型 VS Java对象模型
原文:JVM内存结构 VS Java内存模型 VS Java对象模型 Java作为一种面向对象的,跨平台语言,其对象.内存等一直是比较难的知识点.而且很多概念的名称看起来又那么相似,很多人会傻傻分不清 ...
- 【转】JVM内存结构 VS Java内存模型 VS Java对象模型
JVM内存结构 我们都知道,Java代码是要运行在虚拟机上的,而虚拟机在执行Java程序的过程中会把所管理的内存划分为若干个不同的数据区域,这些区域都有各自的用途. 其中有些区域随着虚拟机进程的启动而 ...
- Java内存模型及Java关键字 volatile的作用和使用说明
先来看看这个关键字是什么意思:volatile [ˈvɒlətaɪl] adj. 易变的,不稳定的; 从翻译上来看,volatile表示这个关键字是极易发生改变的.volatile是java语言中, ...
- JAVA内存模型(Java Memory Model ,JMM)
http://blog.csdn.net/hxpjava1/article/details/55189077 JVM有主内存(Main Memory)和工作内存(Working Memory),主内存 ...
- JVM内存结构 VS Java内存模型 VS Java对象模型
前面几篇文章中, 系统的学习了下JVM内存结构.Java内存模型.Java对象模型, 但是发现自己还是对这三者的概念和区别比较模糊, 傻傻分不清楚.所以就有了这篇文章, 本文主要是对这三个技术点再做一 ...
- 区分 JVM 内存结构、 Java 内存模型 以及 Java 对象模型 三个概念
本文由 简悦 SimpRead 转码, 原文地址 https://www.toutiao.com/i6732361325244056072/ 作者:Hollis 来源:公众号Hollis Java 作 ...
- [转帖]JVM内存结构 VS Java内存模型 VS Java对象模型
JVM内存结构 VS Java内存模型 VS Java对象模型 https://www.hollischuang.com/archives/2509 Java作为一种面向对象的,跨平台语言,其对象.内 ...
- 【Java虚拟机6】Java内存模型(Java篇)
什么是Java内存模型 <Java虚拟机规范>中曾试图定义一种"Java内存模型"(Java Memory Model,JMM)来屏蔽各种硬件和操作系统的内存访问差异, ...
随机推荐
- ts常用数据类型
1.1 布尔值 let isTrue: boolean = false; console.log(isTrue); 1.2 数字 let age: number = 26; console.log(a ...
- 02Javascript变量和数据类型
1. 变量概述 1.1 什么是变量 通俗:变量是用于存放数据的容器. 我们通过 变量名 获取数据,甚至数据可以修改. 1.2 变量在内存中的存储 本质:变量是程序在内存中申请的一块用来存放数据的空间. ...
- Python当中的array数组对象
计算机为数组分配一段连续的内存,从而支持对数组随机访问:由于项的地址在编号上是连续的,数组某一项的地址可以通过将两个值相加得出,即将数组的基本地址和项的偏移地址相加.数组的基本地址就是数组的第一项的机 ...
- Xcode打印如下错误:Unbalanced calls to begin/end appearance transitions 解决办法
今天在做自己的项目时遇到如下错误,项目运行以后,打印台打印如下: Unbalanced calls to begin/end appearance transitions for <HomeVi ...
- [b0021] python 归纳 (七)_获得进程和线程信息
# -*- coding: utf-8 -*- """ 获得线程, 进程 ID,NAME 总结: """ import threading ...
- [Go] gocron源码阅读-判断是否使用root用户执行
判断是linux系统,并且uid为0,allowRoot是通过命令行传参传进来的,通过flag包解析出来的,可以使用go run node.go -h看到这些参数 && !allowR ...
- 安装fiddler后,willow安装
willow 安装需要与fiddler安装在同一个磁盘,如果出现报错找不到路径,请按下面地址下载willow后重新安装 willow下载地址: https://github.com/QzoneTouc ...
- Vue工程化入口文件main.js中Vue.config.productionTip = false含义
阻止启动生产消息,常用作指令.通俗理解为消息提示的环境配置. 阻止启动生产消息 這又是什麽意思? 看下效果 (1)Vue.config.productionTip = false (2)Vue.con ...
- GET POST 区分
get传送的数据量较小,不能大于2KB.post传送的数据量较大,一般被默认为不受限制.但理论上,IIS4中最大量为80KB,IIS5中为100KB. get安全性非常低,get设计成传输数据,一般都 ...
- 201871010110-李华《面向对象程序设计(java)》第十七周学习总结
博文正文开头格式:(2分) 项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.co ...