java中共享变量的可见性:volatile与synchronized 

1. volatile 由关键字volatile修改的线程共享变量具有内存可见性,每次读取此变量时都会从主内存中读取,每次修改此变量时都会写到主内内存中,是真正的在任何时候都具有可见性。原理:在执行cpu命令层面应用CAS算法,实现原子性。

2. final final 修饰变量时,初衷是告诉编译器:这个变量生而不变,可以可劲儿优化,对于boolean,int等类型变量没有问题,但对于List等对象就不会保证可见性当我们修改List中元素时;而volatile是对于包括List的所有类型都具有可见性;

3. synchronized 

以下内容引用于https://www.cnblogs.com/hupu-jr/p/8397911.html,有少许修改。

最近在看<Java并发编程实战>这本书,看到共享变量的可见性,其中说到“加锁的含义不仅仅局限于互斥行为,还包括内存可见性”。

我对于内存可见性第一反应是volatile:被volatile修饰的变量能够保证每个线程能够获取该变量的最新值,从而避免出现数据脏读的现象。

原因是volatile修饰的共享变量进行写操作的时候会多出Lock前缀的指令,通过多处理器的缓存一致性协议,来保持变量的同步更新。

但是我却没明白“加锁”与“可见性”这句话表达的意思,仔细思考下确实是这样子的:

2个线程中在对共享变量的读取或者写入都进行加锁处理,因为线程对应的都是同一把锁对象,所以相互会排斥。但是就算这样子也不能说明内存可见性的。其实真正解决这个问题的是JMM关于Synchronized的两条规定: 

1、线程解锁前,必须把共享变量的最新值刷新到主内存中; 
2、线程加锁时,将清空工作内存中共享变量的值,从而使用共享变量需要从主内存中重新读取最新的值(加锁与解锁需要统一把锁) 

线程执行互斥锁代码的过程: 
1.获得互斥锁 
2.清空工作内存 
3.从主内存拷贝最新变量副本到工作内存 
4.执行代码块 
5.将更改后的共享变量的值刷新到主内存中 
6.释放互斥锁 

http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#incorrectlySync

这里提到synchronized会保证对进入同一个监视器的线程保证可见性。比如线程 t1修改了变量,退出监视器之前,会把修改变量值v1刷新的主内存当中;当线程t2进入这个监视器时,如果有某个处理器缓存了变量v1,首先缓存失效,然后必须重主内存重新加载变量值v1(这点和volatile很像)。这里语义的解读只是说了对于同一个监视器,变量的可见性有一定的方式可寻,非同一个监视器就不保证了。

三、总结

synchronized具有内存可见性,为了确保所有线程能够看到共享变量的值是最新的,所有执行读操作或写操作的线程都必须在同一个锁上同步。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值