并发编程二:JMM的三大特性

并发编程二:JMM的三大特性

1.原子性

指一个操作是不可中断的,即使是多个线程一起执行的时候,一个操作一旦开始,就不会被其他线程干扰,要么全成功,要么全失败。

Java 内存模型保证了 read、load、use、assign、store、write、lock 和 unlock 操作具有原子性,例如对一个 int 类型的变量执行 assign 赋值操作,这个操作就是原子性的。但是 Java 内存模型允许虚拟机将没有被 volatile 修饰的 64 位数据(long,double)的读写操作划分为两次 32 位的操作来进行(高低位是分开赋值),即 load、store、read 和 write 操作可以不具备原子性。

2.可见性

指在多线程环境下,当一个线程修改了共享内存中某一个共享变量的值,其他线程是否能够立即知道这个修改。

显然,对于串行程序来说(单线程环境),可见性问题是不存在。因为你在任何一个操作步骤中修改某个变量,那么在后续的步骤中,读取这个变量的值,一定是修改后的新值。
但是这个问题在并行程序中就不见得了。如果一个线程修改了某一个全局变量,那么其他线程未必可以马上知道这个改动。

主要有有三种实现可见性的方式:

  • volatile,会强制将该变量自己和当时其他变量的状态都刷出缓存
  • synchronized,对一个变量执行
  • unlock, 操作之前,必须把变量值同步回主内存
  • final,被 final 关键字修饰的字段在构造器中一旦初始化完成,并且没有发生 this
    逃逸(其它线程通过 this 引用访问到初始化了一半的对象),那么其它线程就能看见 final 字段的值

3有序性

对于一个线程的执行代码而言,我们总是习惯地认为代码的执行时从先往后,依次执行的。这样的理解也不能说完全错误,因为就一个线程而言,确实会这样。

但是在并发时,程序的执行可能就会出现乱序。给人直观的感觉就是:写在前面的代码,会在后面执行。有序性问题的原因是因为程序在执行时,可能会进行指令重排(happen-before),重排后的指令与原指令的顺序未必一致。

指令重排(happen-before):是指在程序执行过程中, 为了性能考虑, 编译器和CPU可能会对指令重新排序.

指令重排(happen-before)的表现:

  • 代码的执行顺序
  • unlock必须发生在lock之后
  • volatile修饰的变量,写操作要优先于读操作
  • 传递规则,操作a先于b,b先于c,那么a肯定先于c
  • 线程的启动规则,start方法先于线程的其他任意操作
  • 线程的中断规则,interrupt动作,必须发生在捕获改动作之前
  • 对象的销毁规则,初始化必须发生在finalize之前
  • 线程终结规则,所有的操作都要发生在线程死亡之前
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值