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 :如果两个线程(假设t1t2 )正在访问同一个对象,并更新一个被声明为静态的variables,那么它意味着t1t2可以在它们各自的对象(包括静态variables)caching,所以由t1所做的更新到本地caching中的静态variables将不会反映在t2caching的静态variables中。

静态variables在Object上下文中使用,其中由一个对象进行的更新将反映在同一个类的所有其他对象中, 但不在Thread的上下文中,其中一个线程更新为静态variables将立即反映所有线程(在本地caching中)。

易失variables :如果两个线程(假设t1t2 )正在访问同一个对象并更新一个被声明为volatile的variables,那么这意味着t1t2可以创build它们自己的对象的本地caching, 除了被声明为volatile 。 所以volatilevariables只有一个主副本会被不同线程更新,一个线程更新volatilevariables会立即反映到另外一个主线程。

除了其他的答案之外,我想为它添加一个图片(图片容易理解)

在这里输入图像描述

staticvariables可以被caching为单独的线程。 在multithreading环境中, 如果一个线程修改了它的caching数据,那么可能不会反映其他线程,因为它们有一个副本

volatile声明确保线程不会caching数据并使用共享副本

图像源

我认为静态和volatile是毫无关系的。我build议你阅读java教程来理解Atomic Access ,为什么要使用primefaces访问,了解什么是交错的 ,你会发现答案。

简单来说,

  1. 静态 : staticvariables与关联,而不是与任何对象关联。 每个类的实例共享一个类variables,它位于内存中的一个固定位置

  2. volatile :该关键字适用于实例variables。

使用volatilevariables可以降低内存一致性错误的风险,因为任何对volatilevariables的写操作都会build立一个before-before关系,并且随后读取同一个variables。 这意味着对其他线程总是可见的对volatilevariables的更改

看看Javin Paul这篇文章 ,以更好的方式了解volatilevariables。

在这里输入图像描述

如果没有volatile关键字,则每个线程堆栈中的variables值可能不同。 通过将variables设置为volatile ,所有线程将在其工作内存中获得相同的值,并避免了内存一致性错误。

这里术语variable可以是static (类)variables或instance (对象)variables。

关于你的查询:

无论如何,一个静态variables值也将成为所有线程的一个值,那么为什么我们应该去挥发?

如果我的应用程序需要instancevariables,我不能使用staticvariables。 即使在staticvariables的情况下,由于如图所示的线程caching,一致性也不能保证。

使用volatilevariables可以降低内存一致性错误的风险,因为任何对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线程