它是正确的说, static
意味着所有对象的值的一个副本, volatile
意味着所有线程的值的一个副本?
反正一个static
变量值也将是所有线程的一个值,那么我们又何必去volatile
?
它是正确的说, static
意味着所有对象的值的一个副本, volatile
意味着所有线程的值的一个副本?
反正一个static
变量值也将是所有线程的一个值,那么我们又何必去volatile
?
声明在Java中一个静态变量,这意味着将有只有一个副本,不管如何创建类的许多对象。 变量是可以访问的,没有Objects
创建的。 但是,线程可能已经缓存在本地的IT价值。
当一个变量是易失性和不是静态的 ,将会有每一个一个可变Object
。 因此,从表面上看,似乎从没有一个正常的变量差异,但是从静态的完全不同。 然而,即使有Object
的字段,一个线程可以缓存在本地变量值。
这意味着,如果两个线程同时更新同一对象的一个变量,该变量不声明不稳定,有可能是在线程中的一个缓存有一个旧值的情况下。
即使你通过多个线程同时访问一个静态值,每个线程都可以有本地缓存的副本! 为了避免这种情况,你可以声明变量为静态挥发 ,这将迫使线程每次读取全局值。
然而, 挥发性不是正确同步的替代品!
例如:
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
缓存。
静态变量在对象的上下文中使用,其中的一个对象所做的更新将反映在同一类的其他所有对象,但不是在线程的上下文中 ,其中一个线程静态变量的更新会立即反映更改所有线程(在其本地缓存)。
挥发性变量 :如果两个线程(假设t1
和t2
)正在访问相同的对象和更新其被声明为易失性可变那么这意味着t1
和t2
可以使对象的自己的本地高速缓存,除了其被声明为易失性可变 。 所以,volatile变量将只有一个,这将通过一个线程对volatile变量由不同的线程和更新进行更新主副本将立即反映给其他线程。
除了其他的答案,我想补充一个像它(PIC使得容易理解)
static
变量可以被缓存单个线程。 在多线程环境中,如果一个线程修改了它的缓存数据,因为他们有它的一个副本,可能不适合其他线程反映 。
volatile
声明使得线程不会缓存数据,并且只使用共享副本 。
源图像
我认为, static
和volatile
没有关系的。 我建议你阅读Java教程,了解原子访问 ,以及为什么使用原子访问,明白了什么是交错的 ,你会找到答案。
简单来说,
静态 : static
变量与类相关联,而不是与任何对象 。 所述类的每个实例共享一个类的变量,它是在一个固定的位置中的存储器
挥发性 :此关键字同时适用于类和实例变量。
使用volatile变量降低了内存一致性错误的风险,因为volatile变量任何写入建立之前发生同一个变量的随后关系读取。 这意味着,改变volatile变量总是可见的其他线程
看看这个文章通过Javin Paul
了解以更好的方式volatile变量。
在不存在的volatile
的关键字,变量在每个线程的堆栈的值可以是不同的。 通过使变量volatile
,所有的线程将在其工作记忆和内存一致性错误得到相同的值是可以避免的。
这里,术语variable
可以是static
(类)变量或instance
(对象)的变量。
关于您的查询:
反正一个静态变量值也将是所有线程的一个值,那么我们又何必去挥发?
如果我需要instance
在我的应用程序变量,我不能用static
变量。 即使在情况下static
变量,如该图所示的一致性不能保证由于线程缓存。
使用volatile
变量减少了内存一致性错误的风险,因为volatile变量任何写入建立之前发生同一个变量的随后关系读取。 这意味着,改变volatile变量总是给其他线程可见。
更重要的是,这也意味着,当一个线程读取volatile变量,它看到不仅仅是最新的变化挥发,而且代码的副作用,导致了变化=> 内存一致性错误依旧可能带有volatile变量 。 为了避免副作用,你必须使用同步的变量。 但现在没有在java更好的解决方案。
使用简单的原子变量访问比通过同步代码访问这些变量更高效
一些在类中java.util.concurrent
包提供不依赖同步原子的方法。
请参阅本高水平的并发控制更多细节的文章。
特别是看看原子变量 。
相关SE的问题:
挥发性Vs的原子
挥发性布尔VS的AtomicBoolean
挥发性和Java中同步的区别
易失性可变值访问将是从主存储器直接。 它应该只在多线程环境中使用。 静态变量将被加载一次。 如果它在单个线程环境中使用,即使变量的副本将被更新,不会有坏处访问它,因为只有一个线程。
现在,如果静态变量在多线程环境中使用,如果一个预期期望从它的结果,那么就会出现问题。 因为每个线程都有自己的副本,然后从一个线程的静态变量任何增量或减量可能不会在另一个线程反映。
如果一个人指望从静态变量所需的结果的话,在使用挥发性静态多线程那么一切都将得到解决。
如果一个变量声明为静态的,会出现只有一个变量的副本。 所以,当不同的线程访问变量,将会有只有一个变量终值(因为只有一个分配给变量的存储位置)。
如果一个变量声明为挥发,所有线程都会有自己的变量副本,但价值从主memory.So采取变量的值在所有的线程将是相同的。
因此,在这两种情况下,主要的一点是,该变量的值是所有线程相同。