JVM学习篇(3)之Java内存模型与线程

来源:互联网 发布:java 读取jar中的文件 编辑:程序博客网 时间:2024/06/04 19:38

Java内存模型与线程

内存模型(规定多线程对共享变量的使用规则)

模型

目的:定义程序中各个变量的访问规则


1.        所有变量都存储在主内存在。

2.        每条线程都有自己的工作内存,工作内存中保存了被线程使用变量的主内存副本。

3.        线程对变量的操作都在工作内存中进行。

4.        不同线程不能直接访问其它线程的工作内存。

内存间的交互操作


1.        共有8种原子操作

1)        Lock(锁定):作用于主内存变量,表示被一条线程独占状态。

2)        Unlock(解锁):作用于主内存变量,释放处于锁定状态的变量

3)        Read(读取):作用于主内存变量,将变量从内存传输到工作内存。

4)        Load(载入):作用于工作内存,将read操作得到的变量存入工作内存中。

5)        Use(使用):作用于工作内存,将工作内存中的变量传递给执行引擎。

6)        Assign(赋值):将执行引擎中的变量赋给工作内存中的变量

7)        Store(存储):作用于工作内存,将工作内存中的变量传送到主内存中。

8)        Write(写入):作用于主内存变量,将store获得的变量写入到主内存中。

2.        8种操作必须满足如下规则:

1)        不允许从主内存中读取变量,但工作内存不接受。或者从工作内存中发起写会操作,但主内存不接受。(read和load、store和write不能单独出现,必须成对出现)。

2)        不允许一个线程丢弃它最近的assign操作。

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

4)        一个新的变量只能在主内存中诞生。

5)        执行相同的unlock操作后才能解锁。

6)        如果一个变量执行lock操作,则将会清空工作内存中的变量值,在执行引擎使用这个变量是需要重新load。

7)        先lock才能unlock。

8)        对一个变量unlock之前,必须把此变量同步回主内存中。

Volatile型变量特点

1.        保证此变量对所有线程的可见性。(即一个线程修改了这个变量的值,新值对于其它线程立即可知)

1)        虽然volatile变量对在各个线程的中作内存中不存在不一致问题,但由于Java里面的运算并非原子操作,导致volatile变量的运算在并发下一样是不安全的。

2)        使用场景:

a)        运算结果不依赖变量的当前值(条件表达式中的boolean,可见即可,不用来运算)

b)        变量不需要与其他的状态变量共同参与不变约束。

2.        禁止指令的重排序优

1)        一般变量只能保证在该方法的执行过程中所有依赖赋值结果的地方都能获得正确的结果,但不保证赋值的顺序与执行顺序一致。这样在多线程中可能导致某个开关变量被提前赋值,从而出现错误。

3.        性能:

读:volatile变量的读操作的性能消耗与普通变量几乎没有区别,

写:会慢一些。因为他需要在本地代码中插入许多内存屏蔽指令来保证处理器不发生乱序执行。

4.        Volatile变量定义特殊规则总结:

1)        要求线程每次使用volatile变量时,都必须让工作内存从内存中获得。

2)        每次修改volatile变量后,必须立刻同步回主内存中。

3)        要求volatile修饰的变量不会被指令重排序优化,保证执行顺序与程序顺序一致。

内存模式特征

Java内存模型是围绕着在并发过程中如何处理【原子性】、【可见性】和【有序性】。

1.        原子性:通过8个内存操作实现。

2.        可见性:一个线程修改共享变量的值,其它线程能够立即知道这个修改。

1)        Java内存模型是通过在变量修改后将新值同步回主内存,在变量读取前从主内存刷新变量值,依赖主内存为传递媒介来实现可见性。

2)        Volatile 变量可保证多线程的可预见性,普通变量不能保证这一点。

3)        Synchronized通过unlock之前需要把数据同步回主内存中这一规则实现这一点。

3.        有序性:java程序的天然有序性------如果在线程内观察,所有的操作都是有序的,如果在一个线程中观察另一个线程,所有操作都是无序的。

1)        Java语言提供了volatile和synchronized来保证线程之间操作的有序性。

2)        Volatile:本身包含了禁止指令重排序的语义。

3)        Synchronized:由一个变量在同一时刻只允许一个线程对其进行lock操作,这条规则实现的。

先行原则

1.        存在的原因:如果java内存模型所有的有序性都依靠volatile和synchronized来实现,有些操作就会变得很繁琐。

2.        定义:它是Java内存模型中定义的两项操作之间的偏序关系。JVM不能对满足偏序关系的操作进行重新排序。

3.        内容:

1)        程序次序规则:在一个线程内,按着控制流顺序执行。

2)        管程锁定规则:一个unlock操作先行发生于后面对同一个锁的lock操作。

3)        Volatile变量规则:对一个volatile变量的写操作先行发生于后面对这个变量的读操作。

 

4)        线程启动规则:Thread的start方法先行发生于此线程的每个动作。

5)        线程终止规则:线程中所有操作先行发生于对此线程的终止检测。

6)        线程中断规则:对线程的interrupt方法调用先行发生于中断线程检测~中断事件的发生。

7)        对象终结规则:对象的初始化先行于finalize方法的执行。

8)        传递性

Java多线程

线程的实现

线程的实现有三种方式:使用内核线程实现、使用用户线程实现、使用用户线程和轻量级进程实现。

1.        内核线程实现:

1)        内核线程:直接由内核【创建】,并由内核完成【线程的切换】,内核通过线程调度器进行【调度】,并负责映射到各个【处理器中】。

2)        内核线程提【供轻量级进程】给程序使用,来实现线程。


3)        局限性

a)        对线程的操作都是通过内核线程完成的,过每次都需要系统调用,【开销大】。即需要内核态和用户态之间的切换。

b)        每一个线程对应一个内核线程,【销毁内核资源大】。不能支持大规模线程并发。

 

2.        使用用户线程实现

1)        优势:不需要内核线程的支持,支持大规模线程并发。

2)        劣势:没有内核的支持,多有线程的操作都需要用户来实现。(相当复杂,已废弃)

3.        使用用户线程和轻量级进程混合实现

优点:支持大规模线程并发,简化了线程的实现。因为将线程的调度、处理器的映射等复杂操作交由轻量级进程实现。

Java线程

1.        实现:基于操作系统原生线程模型来实现的。(即上面3中之一)。

线程的调度:Java采用的是抢占式调度
1 0
原创粉丝点击