静态意味着所有对象的值的一个副本,而volatile意味着所有线程的值的一个副本,这是正确的吗?
不管怎样,一个静态变量值对于所有线程来说都是一个值,那为什么我们要用volatile呢?
静态意味着所有对象的值的一个副本,而volatile意味着所有线程的值的一个副本,这是正确的吗?
不管怎样,一个静态变量值对于所有线程来说都是一个值,那为什么我们要用volatile呢?
当前回答
我认为静态和不稳定根本没有关系。我建议你阅读java教程了解原子访问,以及为什么使用原子访问,了解什么是交错,你会找到答案。
其他回答
Static和Volatile的区别:
静态变量:如果两个线程(假设t1和t2)正在访问同一个对象,并更新一个被声明为静态的变量,那么这意味着t1和t2可以在各自的缓存中创建相同对象(包括静态变量)的本地副本,因此t1对其本地缓存中的静态变量的更新不会反映在t2缓存的静态变量中。
静态变量用于Object的上下文中,其中一个对象所做的更新将反映在同一类的所有其他对象中,但不用于Thread的上下文中,其中一个线程对静态变量的更新将立即反映到所有线程(在它们的本地缓存中)。
Volatile变量:如果两个线程(假设t1和t2)正在访问同一个对象,并更新一个声明为Volatile的变量,那么这意味着t1和t2可以创建他们自己的对象本地缓存,除了声明为Volatile的变量。因此volatile变量只有一个主副本,它将由不同的线程更新,一个线程对volatile变量的更新将立即反映到另一个线程。
在Java中声明一个静态变量,意味着无论创建了多少个类的对象,都将只有一个副本。即使没有创建任何对象,也可以访问该变量。但是,线程可以在本地缓存它的值。
当一个变量是volatile而不是static时,每个Object都有一个变量。因此,从表面上看,它似乎与正常变量没有区别,但与静态变量完全不同。然而,即使使用Object字段,线程也可以在本地缓存变量值。
这意味着如果两个线程同时更新同一个Object的变量,并且变量没有被声明为volatile,则可能会出现其中一个线程缓存了旧值的情况。
即使您通过多个线程访问静态值,每个线程也可以有其本地缓存副本!为了避免这种情况,你可以将变量声明为static volatile,这将强制线程每次读取全局值。
然而,volatile并不能代替正确的同步! 例如:
private static volatile int counter = 0;
private void concurrentMethodWrong() {
counter = counter + 5;
//do something
counter = counter - 5;
}
多次并发执行concurrentMethodWrong可能导致counter的最终值不为零! 要解决这个问题,你必须实现一个锁:
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类。
我认为静态和不稳定根本没有关系。我建议你阅读java教程了解原子访问,以及为什么使用原子访问,了解什么是交错,你会找到答案。
易失性变量值的访问将直接从主存储器。它应该只在多线程环境中使用。 静态变量将被加载一次。如果它在单线程环境中使用,即使变量的副本将被更新,访问它也不会有任何伤害,因为只有一个线程。
现在,如果静态变量在多线程环境中使用,那么如果有人期望从它得到想要的结果,就会出现问题。由于每个线程都有自己的副本,因此一个线程对静态变量的任何增量或减量可能不会反映在另一个线程中。
如果一个人期望从静态变量得到想要的结果,那么在多线程中使用volatile和static,那么一切都将得到解决。
除了其他的答案,我想为它添加一张图片(图片方便理解)
可以为单个线程缓存静态变量。在多线程环境中,如果一个线程修改了它的缓存数据,这可能不会反映给其他线程,因为他们有一个副本。
Volatile声明确保线程不会缓存数据,只使用共享副本。
图片来源