JMM(Java内存模型)---线程安全极概念浅析杂记

由于CPU有多级缓存 处理器为了提高运算速度,做出了违背代码原有顺序在多核时代多线程下使得计算不准确会发生。

Java虚拟机提供了一套统一的标准让不同的虚拟机,不同的CPU上代码运行结果一致,这个标准就是Java内存模型

(Java Memory Model,简称JMM),它规定了一个线程如何和何时可以看到其他线程对共享变量的修改以及在必要的时候如何同步访问共享变量。

Java内存模型的有8种操作:

1.锁定(Lock):作用于主存中的变量,把一个变量标识成一个线程独占状态。

2.解锁(Unlock):作用于主存中的变量,把一个处于锁定状态的变量释放出来,此变量才能被其他线程锁定。

3.读(Read):作用于主存中的变量,把一个变量值从主存中传递到线程的工作内存中,以便于随后的Load使用。

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

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

6.赋值(Assign):作用于工作内存中的变量,将从执行引擎接收到的值赋值给工作内存中变量。

7.存储(Store):作用于工作内存中的变量,将工作内存的一个变量的值传送主存中,以便于随后的write操作。

8.写入(Write):作用于主存中的变量,将store操作从工作内存中的一个变量值传递到主存的变量中。

对应的同步规则:

如果要把一个变量从主存复制值工作内存中,就需要按顺序地执行read和load操作,如果把变量从工作内存同步到主存中,就要按顺序的store和write操作,但是Java内存模型只要求上述操作必须是按顺序执行,没有保证必须是连续执行。

不允许read和load、store和write操作之一单独出现,即他们都是成对出现的

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

不允许一个线程无原因的(没有发生任何assign操作)把数据从工作内存同不回主存中

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

一个变量在同一时刻只允许一个线程对其进行lock操作,但lock操作可以被同一线程重复执行多次,多次执行lock后,只有执行了相同次数的unlock操作后变量才会被解锁,lock和unlock必须成对出现

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

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

对一个变量执行unlock操作前,必须先把变量同步到主存中(store和write操作)

 

JMM将内存分为堆和栈

:主要是存放基本类型变量,堆地址的引用(对象句柄),数据是可以共享的,速度快,大小和生存期是确定的,JMM要求调用栈和本地变量存放在线程栈上

:运行是数据区,动态分配的,GC自动回收不可达的数据,速度慢

 堆在JDK1.8之前分为年轻代和老年代,JDK 1.8 +(含)老年代变成元空间了不再堆内存中保存,直接存储在主存中了。年轻代又分为伊甸园区和存活区

不同的线程访问同一个对象的方法对的属性,能访问到的都是该对象的私有拷贝。

JMM中是允许编译器对指令进行重排序的,这些重排序不会影响单线程运行,却会影响到多线程的并发执行。

线程安全:

 当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程是如何交替执行,并且不需要在主线程中进行任何额外的同步或者协同,这个类都能表现出正确的期待结果,那么这个类就是线程安全的。

线程安全主要体现在三个方面:

原子性:提供了互斥访问,同一时刻只能有一个线程对其进行操作,能保证原子性的方式 :JDK atomic包(采用CAS算法实现),synchronized,lock

可见性:一个线程对主内存的修改可以及时的被其他线程观察到 保可见性:volatitle、synchronized

有序性:一个线程观察其他线程中的指令的执行顺序,由于指令重排存在,该观察结果一般是杂乱无序的

有序性(hapeens-before原则)

1.程序次序原则:一个线程内,代码会按照书写顺序执行,即代码按行依次执行。(JVM对指令重排序时候会不存数据依赖的进行指令重排序)

2.锁定规则:一个unlock操作一定发生在后续对同一个锁lock操作之前。

3,volatile变量规则:同一个变量的写一定发生在读之前。

4.传递规则:A操作发生在B操作之前,B发生在C之前 ,则A发生在C之前

5.线程启动原则:Thread对象的start()方法先行发生在此线程的每一个动作。

6.线程中断原则:对线程interrupt()方法调用先行于被中断线程的代码检测到中断事件的发生

7.线程终结规则:线程中所有的操作一定在线程终止检测之前。

8.对象终极规则:对象的初始化操作一定在finalize()方法之前。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值