java Volatile

http://tutorials.jenkov.com/java-concurrency/volatile.html

此文章为对此链接的文章内容的概括。

在多线程程序中,共享变量可以被多个线程同时访问。由于编译器的优化机制,如果不对共享变量进行同步操作,那么在多线程程序中就会出现问题,但是在单线程程序中确实能够完好的运行,因为编译器的优化大多都是针对单线程程序的优化的。

一般一个线程在操作非volatile变量(未使用关键字volatile声明的变量)时,可能会先从内存中拷贝该变量到cpu缓存中,再对它操作。如果有多个线程同时操作这个变量,那么在多cpu、多核的环境下会出现多个非volatile变量的副本。此时会出现结果不一致的问题。

如果使用volatile来声明变量,那么每个线程在读取变量时都是直接从内存中读取变量,写入变量时直接写入到内存中(而不是cpu缓存)。此时即使在多线程的环境下,该变量也只有一个副本,不会出现不一致的状况。这也是volatile对所有线程可见性(visibility)的保证。

当然,volatile的作用不止这个,上述只是volatile可见性保证的一部分。比如说,多个变量,其中一个声明为volatile变量。当线程读取该volatile变量时,不仅会从内存中将该变量读取出来,还会将其他非volatile变量从内存读取出来,这样就使得这些变量为最新值。为什么还会有这功能呢?想一想,如果从内存中一次性读入一块数据,是不是更划算?即不降低效率,又增加吞吐量,这和从磁盘读取一块数据而不是一个字节是一样的道理。详细请看链接。

但是编译器有一个优化功能会对这个可见性造成一定麻烦,就是代码的重排序(reordered)。不详细讲这个了,个人感觉了解也没啥太大用处。所以java提供了volatile另外一个保证来解决这个问题,就使保证Happens-Before。个人认为,既然都考虑到了这些问题,何不把剩下的变量都声明为volatile,何必多此一举,把问题复杂化。

volatile只是防止编译器优化造成的问题,对于又竞争条件造成的不同问题,还是需要使用关键值synchronized来解决,或者使用java.util.concurrent包下的原子数据类型,比如AtomicLong或AtomicReference。

由于volatile变量的读写都是从内存中读出或写入的,因此很费时,能不用该变量的时候就不要用了。

猜你喜欢

转载自blog.csdn.net/jdbdh/article/details/81780764