Java 中的可变与静态

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2423622/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 07:26:26  来源:igfitidea点击:

Volatile vs Static in Java

javamultithreadingconcurrencystaticvolatile

提问by Jothi

Is it correct to say that staticmeans one copy of the value for all objects and volatilemeans one copy of the value for all threads?

说这static意味着所有对象的值的volatile一个副本和所有线程的值的一个副本是否正确?

Anyway a staticvariable value is also going to be one value for all threads, then why should we go for volatile?

无论如何,一个static变量值也将是所有线程的一个值,那我们为什么要这样做volatile呢?

采纳答案by stivlo

Declaring a staticvariable in Java, means that there will be only one copy, no matter how many objects of the class are created. The variable will be accessible even with no Objectscreated at all. However, threads may have locally cached values of it.

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

When a variable is volatileand not static, there will be one variable for each Object. So, on the surface it seems there is no difference from a normal variable but totally different from static. However, even with Objectfields, a thread may cache a variable value locally.

当一个变量是volatile而非static 时,每个变量都会有一个变量Object。因此,从表面上看,它似乎与普通变量没有区别,但与static完全不同。然而,即使有Object字段,线程也可以在本地缓存变量值。

This means that if two threads update a variable of the same Object concurrently, and the variable is not declared volatile, there could be a case in which one of the thread has in cache an old value.

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

Even if you access a staticvalue through multiple threads, each thread can have its local cached copy! To avoid this you can declare the variable as static volatileand this will force the thread to read each time the global value.

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

However, volatileis not a substitute for proper synchronisation!
For instance:

然而,volatile并不能代替适当的同步!
例如:

private static volatile int counter = 0;

private void concurrentMethodWrong() {
  counter = counter + 5;
  //do something
  counter = counter - 5;
}

Executing concurrentMethodWrongconcurrently many times may lead to a final value of counter different from zero!
To solve the problem, you have to implement a lock:

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

Or use the AtomicIntegerclass.

或者使用AtomicInteger类。

回答by Jitendra Nalwaya

If we declare a variable as static, there will be only one copy of the variable. So, whenever different threads access that variable, there will be only one final value for the variable(since there is only one memory location allocated for the variable).

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

If a variable is declared as volatile, all threads will have their own copy of the variable but the value is taken from the main memory.So, the value of the variable in all the threads will be the same.

如果变量被声明为 volatile,则所有线程都有自己的变量副本,但该值取自主内存。因此,所有线程中的变量值将相同。

So, in both cases, the main point is that the value of the variable is same across all threads.

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

回答by Som

Difference Between Static and Volatile :

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

Static Variable: If two Threads(suppose t1and t2) are accessing the same object and updating a variable which is declared as static then it means t1and t2can make their own local copy of the same object(including static variables) in their respective cache, so update made by t1to the static variable in its local cache wont reflect in the static variable for t2cache .

静态变量:如果两个线程(假设t1t2)正在访问同一个对象并更新一个声明为静态的变量,那么这意味着t1并且t2可以在各自的缓存中制作自己的同一个对象(包括静态变量)的本地副本,因此更新通过提出t1在其本地缓存中的静态变量在静态变量不会反映t2缓存。

Static variables are used in the context of Objectwhere update made by one object would reflect in all the other objects of the same class but not in the context of Threadwhere update of one thread to the static variable will reflect the changes immediately to all the threads (in their local cache).

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

Volatile variable: If two Threads(suppose t1and t2) are accessing the same object and updating a variable which is declared as volatile then it means t1and t2can make their own local cache of the Object except the variable which is declared as a volatile. So the volatile variable will have only one main copy which will be updated by different threads and update made by one thread to the volatile variable will immediately reflect to the other Thread.

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

回答by Amitābha

I think staticand volatilehave no relation at all. I suggest you read java tutorial to understand Atomic Access, and why use atomic access, understand what is interleaved, you will find answer.

我想staticvolatile根本没有关系。我建议你阅读 java 教程来了解Atomic Access,以及为什么使用原子访问,了解什么是interleaved,你会找到答案。

回答by mrsrinivas

In addition to other answers, I would like to add one image for it(pic makes easy to understand)

除了其他答案,我想为其添加一张图片(图片易于理解)

enter image description here

在此处输入图片说明

staticvariables may be cached for individual threads. In multi-threaded environment if one thread modifies its cached data, that may not reflect for other threads as they have a copyof it.

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

volatiledeclaration makes sure that threads won't cache the data and uses the shared copyonly.

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

image source

图片来源

回答by Ravindra babu

In simple terms,

简单来说,

  1. static: staticvariables are associated with the class, rather than with any object. Every instance of the class shares a class variable, which is in one fixed location in memory

  2. volatile: This keyword is applicable to both classand instancevariables.

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

  2. volatile:此关键字适用于实例变量。

Using volatile variables reduces the risk of memory consistency errors, because any write to a volatile variable establishes a happens-before relationship with subsequent reads of that same variable. This means that changes to a volatile variable are always visible to other threads

使用 volatile 变量可降低内存一致性错误的风险,因为对 volatile 变量的任何写入都会与对该同一变量的后续读取建立先发生关系。这意味着对 volatile 变量的更改始终对其他线程可见

Have a look at this articleby Javin Paulto understand volatile variables in a better way.

看看这篇文章Javin Paul以更好地理解 volatile 变量。

enter image description here

在此处输入图片说明

In absence of volatilekeyword, the value of variable in each thread's stack may be different. By making the variable as volatile, all threads will get same value in their working memory and memory consistency errors have been avoided.

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

Here the term variablecan be either static(class) variable or instance(object) variable.

这里的术语variable可以是static(类)变量或instance(对象)变量。

Regarding your query :

关于您的查询:

Anyway a static variable value is also going to be one value for all threads, then why should we go for volatile?

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

If I need instancevariable in my application, I can't use staticvariable. Even in case of staticvariable, consistency is not guaranteed due to Thread cache as shown in the diagram.

如果instance我的应用程序需要变量,我不能使用static变量。即使在static变量的情况下,由于如图所示的线程缓存,也无法保证一致性。

Using volatilevariables reduces the risk of memory consistency errors, because any write to a volatile variable establishes a happens-before relationship with subsequent reads of that same variable. This means that changes to a volatile variable are always visible to other threads.

使用volatile变量可以降低内存一致性错误的风险,因为对 volatile 变量的任何写入都会与对该同一变量的后续读取建立先发生关系。这意味着对 volatile 变量的更改始终对其他线程可见。

What's more, it also means that when a thread reads a volatile variable, it sees not just the latest change to the volatile, but also the side effects of the code that led up the change => memory consistency errors are still possible with volatile variables. To avoid side effects, you have to use synchronized variables. But there is a better solution in java.

更重要的是,这也意味着当线程读取 volatile 变量时,它不仅会看到 volatile 的最新更改,还会看到导致更改的代码的副作用 => volatile 变量仍然可能出现内存一致性错误. 为了避免副作用,您必须使用同步变量。但是在java中有更好的解决方案。

Using simple atomic variable access is more efficient than accessing these variables through synchronized code

使用简单的原子变量访问比通过同步代码访问这些变量更有效

Some of the classes in the java.util.concurrentpackage provide atomic methods that do not rely on synchronization.

包中的一些类java.util.concurrent提供不依赖于同步的原子方法。

Refer to this high level concurrency controlarticle for more details.

有关更多详细信息,请参阅此高级并发控制文章。

Especially have a look at Atomic variables.

特别是看看Atomic variables

Related SE questions:

相关 SE 问题:

Volatile Vs Atomic

挥发性与原子

Volatile boolean vs AtomicBoolean

挥发性布尔值与原子布尔值

Difference between volatile and synchronized in Java

Java中volatile和synchronized的区别

回答by Aslam anwer

volatile variable value access will be direct from main memory. It should be used only in multi-threading environment. static variable will be loaded one time. If its used in single thread environment, even if the copy of the variable will be updated and there will be no harm accessing it as there is only one thread.

volatile 变量值访问将直接从主内存。它应该只在多线程环境中使用。静态变量将被加载一次。如果它在单线程环境中使用,即使变量的副本将被更新并且访问它也没有坏处,因为只有一个线程。

Now if static variable is used in multi-threading environment then there will be issues if one expects desired result from it. As each thread has their own copy then any increment or decrement on static variable from one thread may not reflect in another thread.

现在,如果在多线程环境中使用静态变量,那么如果期望从中获得所需的结果,就会出现问题。由于每个线程都有自己的副本,因此来自一个线程的静态变量的任何增量或减量可能不会反映在另一个线程中。

if one expects desired results from static variable then use volatile with static in multi-threading then everything will be resolved.

如果人们期望从静态变量获得所需的结果,那么在多线程中使用 volatile 和静态,那么一切都会得到解决。

回答by user2779355

Not sure static variables are cached in thread local memory or NOT. But when I executed two threads(T1,T2) accessing same object(obj) and when update made by T1 thread to static variable it got reflected in T2.

不确定静态变量是否缓存在线程本地内存中。但是当我执行两个线程(T1,T2)访问同一个对象(obj)时,当 T1 线程对静态变量进行更新时,它反映在 T2 中。