Java 复习 —— JMM基础

基本内容

一、共享变量在线程间的可见性安全

二、synchronized实现可见性多线程

三、volatile 实现可见性性能

1)指令重排序优化

2)as-if-serialspa

3)volatile 使用注意事项线程

四、volatile和synchronized的比较对象

一、可见性

一个线程对共享变量值的修改,可以及时地被其余线程看到。排序

共享变量:若是一个变量在多个线程的工做内存中都存在副本,那么这个变量就是这几个线程的共享变量。内存

Java内存模型(JMM):描述了Java程序中各类变量(共享变量)的访问规则,以及在JVM中将变量存储到内存和从内存中读取出变量这样的底层细节。编译器

二、JMM 基本规则

1)全部的变量都存储在在主内存中。

2)每一个线程都有本身独立的工做内存,里面保存该线程使用到的变量副本(主内存中该变量的一份拷贝)。

3)线程对共享变量的全部操做都必须在本身的工做内存中进行,不能直接从主内存中读写

4)不一样线程之间没法直接访问其余线程工做内存中的变量,线程间变量值的传递须要经过主内存来完成。

三、共享变量实现可见性的原理

1)首先在本身线程Thread1里修改共享变量x=1

2)而后更新主内存的x=1

3)其次其余线程Thread2从主内存中读取x=1,更新本身线程的值,

这样连续性的操做,能够保证任何一个线程的独立内存中的共享变量都是最新的值!

四、Java层面实现可见性的方式

1)synchronized

2)volatile

3)concurrent 包

五、synchronized

1)线程解锁前,必须把共享变量的最新值刷新到主内存中

2)线程加锁时,将清空工做内存中共享变量的值,从而使用共享变量时须要从主内存中从新读取最新的值。(注意:加锁与解锁须要同一把锁)

六、synchronized 修饰时,JVM操做的步骤

1)首先得到互斥锁

2)清空工做内存

3)从主内存拷贝变量的最新副本到工做内存

4)执行代码

5)将更改后的共享变量值刷新到主内存

6)释放互斥锁

七、重排序

代码书写的顺序与实际执行的顺序不一样,指令重排序是编译器或处理器为了提升程序性能而作的优化!

1)编译器优化

2)指令优化

3)内存系统优化

最后的结果:有可能致使代码的执行的顺序与编写顺序不一致,可是能够提升CPU性能

八、as-if-serial

不管如何重排序,程序的运行结果都是保持一致的!

单线程中是不能会由于重排序带来内存可见性的问题。

多线程则会因为重排序带来共享变量不一致的问题。

九、致使共享变量在线程间不可见的缘由

1)线程交叉执行。(原子性来保证)

2)重排序结合线程交叉执行。(原子性来保证)

3)共享变量未及时更新。(内存可见性来保证)

十、synchronized 修饰变量、修饰方法或代码块

1)拥有原子性

2)拥有内存可见性

3)重量级

因此他可以实现线程间执行操做的安全性!

十一、volatile 修饰变量

1)不保证原子性

2)拥有可见性

3)轻量级

十二、关于 i++

1)首先读取,从主内存中读取i的值更新到当前工做内存中

2)其次改变,对i进行加1

3)最后更新,从当前工做内存中的值刷新到主内存中去

因此,这不是一个原子操做,在这个操做过程当中势必会致使线程间交互而致使值的混乱!解决方式就是保证 i++ 具备原子性

1)使用synchronized

2)使用Lock对象,concurrent 包中

Lock lock = new RentrantLock();

try{

    lock.lock();

    i++

}finally{

    lock.unlock();

}

1三、volatile 使用场合

1)对变量的写入操做不依赖其当前值,好比Boolean值,可是 i++ 或 i=i+5

2)该变量没有包含在其余变量的不变式中,好比: low < high (这里我也不是很清楚)

注意:共享变量都必须是private

final 也实现了内存可见性,由于他的值是不可修改的!

1四、结论

对一个共享变量不只仅要关心他的写,还关心他的读,两者都要加锁;

volatile是轻量级的,能使用,尽可能使用!

相关文章
相关标签/搜索