在Java中的Volatile和Static区别
在Java中的Volatile和Static区别
说static
意味着为所有对象提供一个值的副本,而volatile
意味着为所有线程提供一个值的副本,这是正确的吗?
无论如何,static
变量值对于所有线程来说也是一个值,为什么我们要选择volatile
呢?
静态变量和易失变量的区别:
静态变量:如果两个线程(假设
静态变量用于对象的上下文中,其中对一个对象的更新将反映在同一类的所有其他对象中,但不用于线程的上下文中,其中对静态变量的一个线程的更新将立即反映在所有线程中(在其本地缓存)。
易失变量:如果两个线程(假设
声明一个Java中的静态变量意味着无论创建该类的对象有多少个,都只会有一个副本。即使没有创建任何对象,该变量也可以访问。但是,线程可能具有本地缓存值。\n\n当一个变量是volatile
而不是static
时,每个Object
都有一个变量。因此,表面上似乎与普通变量没有区别,但与静态变量完全不同。但是,即使对于Object
字段,线程也可能本地缓存变量值。\n\n这意味着如果两个线程同时更新同一个Object的变量,并且该变量未声明为volatile
,则可能存在一个线程在缓存中具有旧值的情况。\n\n即使通过多个线程访问一个static
值,每个线程也可以拥有其本地缓存复制!为避免这种情况,可以将变量声明为static volatile
,这将强制线程每次读取全局值。\n\n但是,volatile
不能代替适当的同步!例如:\n\n
private static volatile int counter = 0; private void concurrentMethodWrong() { counter = counter + 5; //do something counter = counter - 5; }
\n\n同时执行concurrentMethodWrong
很多次可能会导致计数器的最终值与零不同! 为解决此问题,您需要实现锁定:\n\n
private static final Object counterLock = new Object(); private static volatile int counter = 0; private void concurrentMethodRight() { synchronized (counterLock) { counter = counter + 5; } //do something synchronized (counterLock) { counter = counter - 5; } }
\n\n或使用AtomicInteger
类。