Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java中的Volatile与Static_Java_Multithreading_Concurrency_Static_Volatile - Fatal编程技术网

Java中的Volatile与Static

Java中的Volatile与Static,java,multithreading,concurrency,static,volatile,Java,Multithreading,Concurrency,Static,Volatile,如果说static表示所有对象的值的一个副本,而volatile表示所有线程的值的一个副本,那么这样说是否正确 无论如何,静态变量值也将是所有线程的一个值,那么为什么我们要选择volatile?如果我们将变量声明为静态,那么该变量将只有一个副本。 因此,每当不同线程访问该变量时,该变量只有一个最终值(因为只有一个内存位置分配给该变量) 如果一个变量被声明为volatile,那么所有线程都将有自己的变量副本,但是该值是从主存获取的。因此,所有线程中的变量值都是相同的 因此,在这两种情况下,主要的一

如果说
static
表示所有对象的值的一个副本,而
volatile
表示所有线程的值的一个副本,那么这样说是否正确


无论如何,
静态
变量值也将是所有线程的一个值,那么为什么我们要选择
volatile

如果我们将变量声明为静态,那么该变量将只有一个副本。 因此,每当不同线程访问该变量时,该变量只有一个最终值(因为只有一个内存位置分配给该变量)

如果一个变量被声明为volatile,那么所有线程都将有自己的变量副本,但是该值是从主存获取的。因此,所有线程中的变量值都是相同的


因此,在这两种情况下,主要的一点是变量的值在所有线程中都是相同的。

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

当变量是易变的而不是静态的时,每个
对象将有一个变量。因此,表面上看,它似乎与正态变量没有区别,但与静态变量完全不同。但是,即使使用
对象
字段,线程也可能在本地缓存变量值

这意味着,如果两个线程同时更新同一对象的一个变量,并且该变量未声明为volatile,则可能存在这样的情况:其中一个线程的缓存中有一个旧值

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

但是,volatile不能代替正确的同步
例如:

private static volatile int counter = 0;

private void concurrentMethodWrong() {
  counter = counter + 5;
  //do something
  counter = counter - 5;
}
多次并发执行
concurrentMethodError
可能会导致计数器的最终值不同于零
要解决此问题,您必须实现一个锁:

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;
  }
}

或者使用该类。

静态和易失性之间的区别:

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

静态变量在对象的上下文中使用,其中一个对象所做的更新将反映在同一类的所有其他对象中,但不在线程的上下文中使用,其中一个线程对静态变量的更新将立即反映所有线程(在其本地缓存中)的更改


可变变量:如果有两个线程(假设
t1
t2
)正在访问同一对象并更新声明为volatile的变量,则意味着
t1
t2
可以创建对象的本地缓存,声明为volatile的变量除外。因此volatile变量只有一个主副本,它将由不同的线程更新,一个线程对volatile变量所做的更新将立即反映到另一个线程。

我认为
静态
volatile
完全没有关系。我建议你们阅读java教程来理解,以及为什么要使用原子访问,理解什么是原子访问,你们会找到答案。

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

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

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

简单地说

  • 静态
    变量与关联,而不是与任何对象关联。类的每个实例共享一个类变量,该变量位于内存中的一个固定位置

  • :此关键字适用于实例变量

  • 使用易失性变量可以降低内存一致性错误的风险,因为对易失性变量的任何写入都会与该变量的后续读取建立“发生在之前”的关系。这意味着对易失性变量的更改对其他线程总是可见的

    请看一下Javin Paul的文章,以更好地理解易变变量

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

    这里术语
    变量
    可以是
    静态
    (类)变量或
    实例
    (对象)变量

    关于你的问题:

    不管怎样,一个静态变量的值对于所有线程来说也是一个值,那么为什么我们应该选择volatile呢

    如果我的应用程序中需要
    实例
    变量,我就不能使用
    静态
    变量。即使是
    静态
    变量,一致性也很重要