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
类。
静态和挥发之间的区别:
静态变量 :如果两个线程(假设t1
和t2
)正在访问同一个对象并更新一个被声明为静态的变量,那么它意味着t1
和t2
可以在它们各自的对象(包括静态变量)中创建它们自己的本地副本缓存,因此由t1
所做的更新到其本地缓存中的静态变量将不反映在t2
缓存的静态变量中。
静态变量用于Object的上下文中,其中由一个对象进行的更新将反映在同一类的所有其他对象中, 但不在Thread的上下文中,其中一个线程更新为静态变量将立即反映所有线程(在他们的本地缓存中)。
易变变量 :如果两个线程(假设t1
和t2
)正在访问同一个对象并更新一个被声明为volatile的变量,那么它意味着t1
和t2
可以创建它们自己的Object的本地缓存, 除了被声明为volatile的变量 。 所以volatile变量将只有一个主副本,它将被不同的线程更新,一个线程更新到volatile变量会立即反映到另一个线程。
除了其他答案之外,我还想为它添加一个图片(图片易于理解)
static
变量可以被缓存为单独的线程。 在多线程环境中, 如果一个线程修改了它的缓存数据,这可能不会反映其他线程,因为它们有一个副本 。
volatile
声明确保线程不会缓存数据并仅使用共享副本 。
图像源
链接地址: http://www.djcxy.com/p/91969.html