重新认识synchronized和volatile
点关注不迷路,欢迎再来!
一.原子性(Atomic)操作指相应的操作时单一不可分割的操作
例如:对int型变量count执行counter++的操作就不是原子操作。因为counter++可以分解为3个操作:
1.读取counter的当前值;
2.那counter的当前值和1做加法运算;
3.将counter的当前值增加1后的值赋值给counter变量。
二.内存可见性:
CPU在执行代码的时候,为了减少变量的访问时间消耗可能将代码中访问的变量的值缓存到该CPU的缓冲区中。因此
相应代码再次访问某个变量时,相应的值可能从CPU缓存区而不是主内存中读取的。同样的,代码对这些被缓存过的变量值得修改也可能
仅是被写入CPU缓存区,而没有被写回主内存。由于每个CPU都有自己的缓冲区,因此一个CPU缓冲区中的内容对其它CPU而言是不可见的。
这就导致了在其它CPU上运行的其它线程可能无法"看到"该线程对某个变量值所做的更改。
在多线程环境中,非原子操作可能受其它线程的干扰。比如,上述例子如果没有对应的代码同步synchronized处理,
则可能出现在执行第2个操作的时候counter的值已经被其它线程修改了。因此这一步的操作所使用的counter变量
的"当前值"其实已经是过期的了。当然,synchronized关键字可以帮助我们实现操作的原子性,以避免这种线程间的干扰情况。
三.synchronized关键字:
1.可以实现操作的原子性,其本质是通过该关键字所包括的临界区()的排他性保证在任何一个时刻只有一个线程能够执行临界区的代码。
2.保证了一个线程执行临界区中的代码时所修改的变量对于稍后执行该临界区中的代码的线程来说是可见的。
四.volatile关键字:
1.可以保证内存可见性。当一个线程修改了一个volatile修饰的变量的值时,该值会被写入主内存(即RAM)而不仅仅时当前线程所在的
CPU的缓冲区,而其它CPU的缓冲区中存储的该变量的值也会因此是失效(从而得以更新为主内存中的变量的相应值)。
2.禁止指令重排序(Re—order)。虽然导致编译器和CPU无法对一些指令进行可能的优化,但是它某种程度上让代码的执行看起来更符合我们的期望。
五.volatile和synchronized区别:
相同点:都可以保证内存可见性。
不同点:volatile不能保证操作的原子性。