Is volatile necessary when stale values are acceptable?

huangapple go评论67阅读模式
英文:

Is volatile necessary when stale values are acceptable?

问题

我有一个微服务,它接收实时的HTTP请求。这些请求在共享对象上执行读取操作。

此服务还有一个后台作业,用于更新共享对象的引用。

我理解在竞争情况下,一些请求线程可能会在整个请求过程中看到过期的数据,因为数据可能从本地缓存中获取。我的问题是,如果我对几秒钟的过期数据可以接受,是否需要将这个共享对象设置为volatile?

英文:

I have a microservice which receives real time http requests. These requests perform read on a shared Object.

This service also has background job which update the reference of the shared object.

I understand in race some request threads might see stale data for the entire request as data might be picked from local caches. My question is if I am ok with stale data for few seconds, do I need to make this shared Object volatile ?

答案1

得分: 1

所以,你有一个线程(“后台作业”)定期构建一个新对象,然后将其引用存储在全局变量中。

问题在于,你不仅需要担心全局变量的“陈旧”,还要考虑到共享对象的每个单独字段可以独立于其他字段而“陈旧”。共享对象的每个子对象的每个部分都可以独立于任何其他部分而“陈旧”。

如果共享对象不仅仅是一个单一的共享Integer,那么“后台作业”必须逐步构建它。而且,在线程之间没有同步的情况下,查看该对象的任何其他线程可能会看到其中的某些部分“已构建”,而其他部分似乎尚未构建。

没有同步,客户端线程不能保证以“后台作业”执行赋值的相同顺序看到对象的字段更新。较早的赋值可能会出现,而较晚的赋值仍然似乎是“陈旧”的。

假设你有这样的代码:

class SharedObj {
    public int x;
    public int y;

    public static SharedObj globalRef = new SharedObj();
}

并且假设后台线程执行以下操作:

SharedObj localRef = new SharedObj();
localRef.x = 3;
localRef.y = 5;
SharedObj.globalRef = localRef;

最后,在某个其他线程中:

SharedObj localRef = SharedObj.globalRef;
if (localRef.y < localRef.x) {
    System.out.println("Boo!!");
}

其他线程能够打印“Boo!!”吗?是的,它可以。我不知道所有的可能性,但其中一种可能性是,它可能会看到x==3y==0


你可以使用volatile保证程序永远不会打印“Boo!!”:

static volatile SharedObj globalRef = new SharedObj();

这有效是因为volatile的写入和读取在两个线程之间建立了一个“happens before”关系。volatile关键字保证在更新globalRef之前“后台作业”执行的所有操作在其他线程从globalRef读取新引用时对其可见。

英文:

So, you've got one thread (the "background job") that periodically constructs a new object, and then stores a reference to it in a global variable.

The problem is, it's not just the "staleness" of the global variable that you have to worry about. Each individual field of the shared object can be "stale" independently of each other field. Each part of each sub-object can be individually "stale" independent of any other part.

If the shared object is anything more complicated than just a single shared Integer, then the "background job" has to construct it piece-by-piece. And, with no synchronization between the threads, any other thread that looks at that object could see some parts of it "constructed" while other parts appear to be not-yet-constructed.

Without synchronization, the client threads are not guaranteed to see fields of the object updated in the same order in which the background job performed the assignments. An earlier assignment might come through, while a later assignment still appears to be "stale."

Suppose you have this:


class SharedObj {
    public int x;
    public int y;

    public static SharedObj globalRef = new SharedObj();
}

And suppose the background thread does this:

SharedObj localRef = new SharedObj();
localRef.x = 3;
localRef.y = 5;
SharedObj.globalRef = localRef;

Finally, in some other thread:

SharedObj localRef = SharedObj.globalRef;
if (localRef.y &lt; localRef.x) {
    System.out.println(&quot;Boo!!&quot;);
}

Can the other thread print "Boo!!"? Yes. It can. I don't know all of the possibilities, but one possibility is, it could see x==3 and y==0.


You can use volatile to guarantee that the program will never print "Boo!!":

    static volatile SharedObj globalRef = new SharedObj();

It works because volatile writes and reads establish a "happens before" relationship between the two threads. The volatile keyword guarantees that everything the "background job" did before it updated the globalRef must become visible to any other thread when the other thread reads the new reference from the globalRef.

答案2

得分: 0

是的。否则不能保证其他线程会 永远 看到更新后的值。

英文:

Yes. Otherwise there is no guarantee that the updated value will ever be seen by other threads.

huangapple
  • 本文由 发表于 2023年5月25日 20:20:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/76332207.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定