关于volatile关键字,下列描述不正确的是?
正确答案: B D 你的答案: A C (错误)
用volatile修饰的变量,每次更新对其他线程都是立即可见的。
对volatile变量的操作是原子性的。
对volatile变量的操作不会造成阻塞。
不依赖其他锁机制,多线程环境下的计数器可用volatile实现。
一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:
1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。
2)禁止进行指令重排序。
volatile只提供了保证访问该变量时,每次都是从内存中读取最新值,并不会使用寄存器缓存该值——每次都会从内存中读取。
而对该变量的修改,volatile并不提供原子性的保证。
由于及时更新,很可能导致另一线程访问最新变量值,无法跳出循环的情况
多线程下计数器必须使用锁保护。
所谓 volatile的措施,就是1. 每次从内存中取值,不从缓存中什么的拿值。这就保证了用 volatile修饰的共享变量,每次的更新对于其他线程都是可见的。2. volatile保证了其他线程的立即可见性,就没有保证原子性。3.由于有些时候对 volatile的操作,不会被保存,说明不会造成阻塞。不可用与多线程环境下的计数器。
原理:当一个变量被定义为volatile之后,就可以保证此变量对所有线程的可见性,即当一个线程修改了此变量的值的时候,变量新的值对于其他线程来说是可以立即得知的。可以理解成:对volatile变量所有的写操作都能立刻被其他线程得知。但是这并不代表基于volatile变量的运算在并发下是安全的,因为volatile只能保证内存可见性,却没有保证对变量操作的原子性。比如下面的代码:
1234567891011121314151617181920212223242526272829303132333435363738 /*** 发起20个线程,每个线程对race变量进行10000次自增操作,如果代码能够正确并发,* 则最终race的结果应为200000,但实际的运行结果却小于200000。** @author Colin Wang**/public class VolatileTest {public static volatile int race = 0;public static void increase() {race++;}private static final int THREADS_COUNT = 20;public static void main(String[] args) {Thread[] threads = new Thread[THREADS_COUNT];for (int i = 0; i < THREADS_COUNT; i++) {threads[i] = new Thread(new Runnable() {@Overridepublic void run() {for (int i = 0; i < 10000; i++) {increase();}}});threads[i].start();}while (Thread.activeCount() > 1)Thread.yield();System.out.println(race);}}这便是因为race++操作不是一个原子操作,导致一些线程对变量race的修改丢失