Java 中的易失性与静态

发布于 2024-08-25 02:47:17 字数 170 浏览 5 评论 0 原文

static 表示所有对象的值的一份副本,而 volatile 表示所有线程的值的一份副本是否正确?

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

Is it correct to say that static means one copy of the value for all objects and volatile means one copy of the value for all threads?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

猫瑾少女 2024-09-01 02:47:17

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

当变量是易失性且不是静态时,每个对象都会有一个变量。所以,表面上看起来和普通变量没有什么区别,但和静态完全不同。然而,即使使用Object字段,线程也可以在本地缓存变量值。

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

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

然而,易失性并不能替代正确的同步!
例如:

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 类。

Declaring a static variable 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 Objects created at all. However, threads may have locally cached values of it.

When a variable is volatile and 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 Object fields, a thread may cache a variable value locally.

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.

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

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

private static volatile int counter = 0;

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

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

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 AtomicInteger class.

橘寄 2024-09-01 02:47:17

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

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

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

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

Difference Between Static and Volatile :

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

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

Volatile variable: If two Threads(suppose t1 and t2) are accessing the same object and updating a variable which is declared as volatile then it means t1 and t2 can 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.

温柔女人霸气范 2024-09-01 02:47:17

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

在此处输入图像描述

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

易失性 声明确保线程不会缓存数据并仅使用共享副本

图片来源

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

enter image description here

static variables 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 copy of it.

volatile declaration makes sure that threads won't cache the data and uses the shared copy only.

image source

你不是我要的菜∠ 2024-09-01 02:47:17

我认为staticvolatile根本没有关系。我建议你阅读java教程来理解原子访问,并且为什么要使用原子访问,了解什么是交错,你就会找到答案。

I think static and volatile have 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.

捎一片雪花 2024-09-01 02:47:17

简单来说,

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

  2. 易失性:此关键字适用于实例变量。

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

看看这个 Javin Paul 的文章,以更好的方式理解 volatile 变量。

输入图片description here

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

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

关于您的查询:

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

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

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

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

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

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

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

特别要看看原子变量

相关 SE 问题:

Volatile Vs Atomic

Volatile 布尔值与 AtomicBoolean

Java中volatile和synchronized的区别

In simple terms,

  1. static : static variables 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 class and instance variables.

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

Have a look at this article by Javin Paul to understand volatile variables in a better way.

enter image description here

In absence of volatile keyword, 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.

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

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?

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

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.

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.

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

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

Refer to this high level concurrency control article for more details.

Especially have a look at Atomic variables.

Related SE questions:

Volatile Vs Atomic

Volatile boolean vs AtomicBoolean

Difference between volatile and synchronized in Java

狼亦尘 2024-09-01 02:47:17

说静态意味着所有对象的值的一个副本是不正确的,因为静态意味着加载包含类的每个类加载器只有一个副本。

Java volatile 关键字的意思是,对 volatile 变量的每次读取都将从计算机的主内存中读取,而不是从 CPU 缓存中读取,并且对 volatile 变量的每次写入都将写入主内存,而不仅仅是 CPU缓存。

It is incorrect to say that static means one copy of the value for all objects because static means there will be only one copy for each classloader that loads the containing class.

The Java volatile keyword means, that every read of a volatile variable will be read from the computer's main memory, and not from the CPU cache, and that every write to a volatile variable will be written to main memory, and not just to the CPU cache.

梦回旧景 2024-09-01 02:47:17

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

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.

孤君无依 2024-09-01 02:47:17

易失性变量值访问将直接从主存储器进行。它应该只在多线程环境中使用。
静态变量将被加载一次。如果在单线程环境中使用,即使变量的副本会被更新,访问它也不会造成任何损害,因为只有一个线程。

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

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

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.

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.

天邊彩虹 2024-09-01 02:47:17

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

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

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

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.

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文