2.[深入理解JVM笔记]Java内存模型与线程-阿里云开发者社区

开发者社区> 开发与运维> 正文

2.[深入理解JVM笔记]Java内存模型与线程

简介:

1.Java内存模型

Java内存模型用来屏蔽各种硬件和操作系统的内存访问差异,以实现在各种平台下都能达到一致的并发效果。

主内存与工作内存

Java内存模型的主要目标是/定义程序中各个变量的/访问规则,即在虚拟机中/将变量存储到内存和从内存中取出变量这样的底层细节。

Java内存模型规定:

所有的变量都存储在主内存中;

每个线程有自己的工作内存,线程的工作内存保存被线程使用到变量的主内存副本拷贝;

线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存的变量;

不同线程之间不能直接访问对方工作内存中的变量,线程间变量值的传递通过主内存来完成。

223143376.png

内存间交互操作

Java内存模型定义了八种操作

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

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

read(读取):作用于主内存的变量,它把一个变量的值从主内存传送到线程中的工作内存,以便随后的load动作使用;

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

use(使用):作用于工作内存的变量,它把工作内存中一个变量的值传递给执行引擎;

assign(赋值):作用于工作内存的变量,它把一个从执行引擎接收到的值赋值给工作内存中的变量;

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

write(写入):作用于主内存的变量,它把store操作从工作内存中得到的变量的值写入主内存的变量中。

操作时规则

不允许read和load、store和write操作之一单独出现;

说明:如果要把一个变量从主内存复制到工作内存,那要顺序执行read和load操作;如果要把变量从工作内存同步回主内存,就要顺序执行store和write操作。Java内存模型要求上述连个操作必须按顺序执行,但不必须连续执行。

不允许一个线程丢弃它的最近的assign操作,变量在工作内存中改变了之后必须把变化同步回主内存;

不允许一个线程无原因地把数据从线程的工作内存同步回主内存;

一个新变量之能在主内存诞生,不允许在工作内存直接使用一个为被初始化(load或assign)的变量,即在对一个变量实施use和store操作之前,必须先执行assign和load操作;

一个变量在同一个时刻只允许一条线程对其进行lock操作,但lock操作可以被同一线程重复执行多次,多次执行lock后,只有执行相同次数的unlock操作,变量才被解锁;

如果对一个变量执行lock操作,将会清空工作内存中此变量的值,在执行引擎使用这个变量前,需要重新执行load或assign操作初始化变量的值;

如果一个变量事先没有被lock操作锁定,则不允许对他执行unlock操作;也不允许去unlock一个被其他线程锁定住的变量;

对一个变量执行unlock操作之前,必须先把此变量同步回主内存。

volatile

关键字volatile是JVM提供最轻量级的同步机制。

当一个变量被定义成volatile后,它具有两个特性:

第一,volatile变量对所有线程是立即可见的,对于volatile变量所有的写操作都能立刻反应到其他线程之中;但volatile变量只能保证可见性,不能保证在并发下是安全的。

第二,禁止指令重排序优化。

Java模型特性

原子性:J read、load、assign、use、store和write保证原子性变量操作;lock和unlock通过synchronized语法来加锁,在synchronized块之间的操作也具有原子性;

可见性:volatile、synchronized和final实现变量修改值在其他线程可见;synchronized可见性是由“对一个变量执行unlock操作之前,必须先把此变量同步回主内存中“这条规则获得的;final可见性是”被final修饰的字段在构造器中一旦被初始化完成,并且构造器没有把this的引用传递出去,那么在其他线程就能看到final字段的值。“

有序性:Java语言提供volatiel和synchronized两个关键字来保证线程之间的有序性;volatile本身禁止指令重排序;synchronized是由“一个变量在同一个时刻只允许一条线程对其进行lock操作“这条规则获得的。

2.Java与线程

线程是比进程更轻量级的调度执行单位,线程可以把一个进程的资源分配和执行调度分开,各个线程既可以共享进度资源,由可以独立调度。

Java线程实现

Java在Windows与Linux上都是使用一对一的县城模型来实现,一个Java线程就映射到一条轻量级进程之中。

Java线程调度

线程调度指系统为线程分配处理器使用权的过程,主要调度方式分为:协同式和抢占式。Java使用的线程调度方式是抢占式调度。

协同式,线程的执行时间由线程本身来控制,线程执行完之后主动通知系统切换到另一个线程,它的坏处是线程执行时间不可控制。如果一个线程迟迟不让出CPU执行时间会导致整个系统崩溃。

抢占式,每个线程由系统来分配执行时间,线程的切换由操作系统决定。

状态装换

Java定义了5种线程状态,在任意一个时间点,一个县城智能有且只有有其中的一种状态,即:

新建(New):创建后尚未启动的线程;

运行(Runable):包括了操作系统线程状态中的Running和Ready,处于此状态的线程可能正在执行,也可能正在等待CPU为它分配执行时间;

无限期等待(Waiting):该状态的线程不会被分配CPU执行时间,他们要等待其他线程显式唤醒。以下方式可以让线程陷入Waiting状态:

1.没有设置Timeout参数的Object.wat()方法;

2.没有设置Timeout参数的Thread.join()方法;

3.LockSupport.park()方法。

限制等待(Timed Waiting):该状态的线程也不会被分配CPU执行时间,不过无须等待其他线程显示唤醒,在一定时间之后它们会由系统自动唤醒。以下方式可以让线程陷入Timed Waiting状态:

1.Thread.sleep()方法;

2.设置了Timeout参数的Ojbect.wait()方法;

3.设置了Timeout参数的Thread.join()方法;

4.LockSupport.parkNanos()方法;

5.LockSupport.parkUntil()方法。

阻塞(Blocked):线程被阻塞。在程序等待进入同步区域时,线程进入这种状态。

结束(Terminated):终止线程的状态。

223150342.png










本文转自 LinkedKeeper 51CTO博客,原文链接:http://blog.51cto.com/sauron/1228565,如需转载请自行联系原作者

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

分享:
开发与运维
使用钉钉扫一扫加入圈子
+ 订阅

集结各类场景实战经验,助你开发运维畅行无忧

其他文章