Java中的易变Vs静态
是否正确地说, 静态意味着所有对象的值的一个副本, 易失性意味着所有线程的值的一个副本?
无论如何,一个静态variables值也将成为所有线程的一个值,那么为什么我们应该去挥发 ?
在Java中声明一个静态variables意味着只有一个副本,不pipe这个类有多less个对象被创build。 即使没有创buildObjects
,variables也是可访问的。 但是,线程可能具有本地caching的值。
当一个variables是易变的而不是静态的 ,每个Object
将会有一个variables。 所以表面上看起来和普通variables没有什么区别,但是和静态完全不同。 但是,即使使用Object
字段,线程也可以在本地cachingvariables值。
这意味着如果两个线程同时更新同一个对象的一个variables,并且这个variables没有被声明为volatile,那么可能会有一个线程在caching中有一个旧值的情况。
即使您通过多个线程访问静态值,每个线程也可以拥有其本地caching副本! 为了避免这种情况,你可以声明variables为静态variables,这将强制线程读取每次全局值。
但是, volatile不能替代正确的同步!
例如:
private static volatile int counter = 0; private void concurrentMethodWrong() { counter = counter + 5; //do something counter = counter - 5; }
同时多次执行concurrentMethodWrong
可能会导致计数器的最终值不等于零!
要解决这个问题,你必须实现一个锁:
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; } }
或者使用AtomicInteger
类。
静态和挥发之间的区别:
静态variables :如果两个线程(假设t1
和t2
)正在访问同一个对象,并更新一个被声明为静态的variables,那么它意味着t1
和t2
可以在它们各自的对象(包括静态variables)caching,所以由t1
所做的更新到本地caching中的静态variables将不会反映在t2
caching的静态variables中。
静态variables在Object的上下文中使用,其中由一个对象进行的更新将反映在同一个类的所有其他对象中, 但不在Thread的上下文中,其中一个线程更新为静态variables将立即反映所有线程(在本地caching中)。
易失variables :如果两个线程(假设t1
和t2
)正在访问同一个对象并更新一个被声明为volatile的variables,那么这意味着t1
和t2
可以创build它们自己的对象的本地caching, 除了被声明为volatile 。 所以volatilevariables只有一个主副本会被不同线程更新,一个线程更新volatilevariables会立即反映到另外一个主线程。
除了其他的答案之外,我想为它添加一个图片(图片容易理解)
static
variables可以被caching为单独的线程。 在multithreading环境中, 如果一个线程修改了它的caching数据,那么可能不会反映其他线程,因为它们有一个副本 。
volatile
声明确保线程不会caching数据并仅使用共享副本 。
图像源
我认为静态和volatile是毫无关系的。我build议你阅读java教程来理解Atomic Access ,为什么要使用primefaces访问,了解什么是交错的 ,你会发现答案。
简单来说,
-
静态 :
static
variables与类关联,而不是与任何对象关联。 每个类的实例共享一个类variables,它位于内存中的一个固定位置 -
volatile :该关键字适用于类和实例variables。
使用volatilevariables可以降低内存一致性错误的风险,因为任何对volatilevariables的写操作都会build立一个before-before关系,并且随后读取同一个variables。 这意味着对其他线程总是可见的对volatilevariables的更改
看看Javin Paul
这篇文章 ,以更好的方式了解volatilevariables。
如果没有volatile
关键字,则每个线程堆栈中的variables值可能不同。 通过将variables设置为volatile
,所有线程将在其工作内存中获得相同的值,并避免了内存一致性错误。
这里术语variable
可以是static
(类)variables或instance
(对象)variables。
关于你的查询:
无论如何,一个静态variables值也将成为所有线程的一个值,那么为什么我们应该去挥发?
如果我的应用程序需要instance
variables,我不能使用static
variables。 即使在static
variables的情况下,由于如图所示的线程caching,一致性也不能保证。
使用volatile
variables可以降低内存一致性错误的风险,因为任何对volatilevariables的写操作都会build立一个before-before关系,并且随后读取同一个variables。 这意味着对其他线程总是可见的对volatilevariables的更改。
更重要的是,这也意味着当一个线程读取一个volatilevariables时,它不仅会看到volatile的最新变化,还会导致代码的副作用,导致变化=> 内存一致性错误仍然可能发生在volatilevariables 。 为了避免副作用,你必须使用同步variables。 但是在java中有一个更好的解决scheme。
使用简单的primefacesvariables访问比通过同步代码访问这些variables更有效
java.util.concurrent
包中的一些类提供了不依赖于同步的primefaces方法。
有关更多详细信息,请参阅此高级别的并发控制文章。
特别看看Atomicvariables 。
相关的SE问题:
挥发性与primefaces
易失性布尔与AtomicBoolean
Java中volatile和synchronized的区别
volatilevariables值的访问将直接从主存储器中获取。 它只能用于multithreading环境。 静态variables将被加载一次。 如果它在单线程环境中使用,即使variables的副本将被更新,访问它也不会有任何伤害,因为只有一个线程。
现在,如果在multithreading环境中使用静态variables,那么如果期望从它得到期望的结果,则会出现问题。 由于每个线程都有自己的副本,因此一个线程的静态variables的任何增量或减量可能不会反映到另一个线程中。
如果期望从静态variables获得期望的结果,那么在multithreading中使用volatile与static,那么一切都将被解决。
如果我们声明一个variables是静态的,那么只会有一个variables的副本。 因此,只要不同的线程访问该variables,variables只有一个最终值(因为只有一个内存位置分配给该variables)。
如果一个variables被声明为volatile,所有的线程将拥有自己的variables副本,但是这个值是从主内存中获取的。所以,所有线程中variables的值都是相同的。
所以,在这两种情况下,重点是variables的值在所有线程中都是相同的。
声明一个variablesvolatile会保证在不同的体系结构上,jvm不会在本地cachingvariables线程