Java中的易变Vs静态

说静态意味着所有对象的值的一个副本,并且volatile意味着所有线程的值的一个副本是否正确?

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


在Java中声明静态变量意味着只有一个副本,无论该类创建了多少个对象。 即使没有创建Objects该变量也是可访问的。 但是,线程可能具有本地缓存​​的值。

当一个变量是易失性的而不是静态的时候 ,每个Object会有一个变量。 所以,从表面上看,它与普通变量没有区别,但与静态完全不同。 但是,即使使用Object字段,线程也可以在本地缓存变量值。

这意味着如果两个线程同时更新同一个对象的一个​​变量,并且该变量没有被声明为volatile,那么可能会出现这样的情况,其中一个线程在缓存中有一个旧值。

即使您通过多个线程访问静态值,每个线程也可以拥有本地缓存​​副本! 为了避免这种情况,你可以声明变量为静态变量,这将强制线程读取每次全局值。

但是, 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类。


静态和挥发之间的区别:

静态变量 :如果两个线程(假设t1t2 )正在访问同一个对象并更新一个被声明为静态的变量,那么它意味着t1t2可以在它们各自的对象(包括静态变量)中创建它们自己的本地副本缓存,因此由t1所做的更新到其本地缓存中的静态变量将不反映在t2缓存的静态变量中。

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

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


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

在这里输入图像描述

static变量可以被缓存为单独的线程。 在多线程环境中, 如果一个线程修改了它的缓存数据,这可能不会反映其他线程,因为它们有一个副本

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

图像源

链接地址: http://www.djcxy.com/p/91969.html

上一篇: Volatile Vs Static in java

下一篇: Volatile vs. Interlocked vs. lock