0

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 ?

Thomas
  • 174,939
  • 50
  • 355
  • 478
Manas Saxena
  • 2,171
  • 6
  • 39
  • 58
  • Does this answer your question? [Volatile read and non-volatile fields](https://stackoverflow.com/questions/45602130/volatile-read-and-non-volatile-fields) – Hulk May 25 '23 at 12:41

2 Answers2

1

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 < localRef.x) {
    System.out.println("Boo!!");
}

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.

Solomon Slow
  • 25,130
  • 5
  • 37
  • 57
0

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

Thomas
  • 174,939
  • 50
  • 355
  • 478
  • These are http threads which hve short life span and are stateless. After few seconds newer http requests should start seeing the updated data right ? – Manas Saxena May 25 '23 at 13:18
  • 1
    @ManasSaxena that will depend on whether they are really short-lived or perhaps pooled somehow, and which kind of synchronisation happens internally in the thread pool. I'd rather not rely on that. Also, it is clearer from a code style perspective to just add the volatile flag, making it clear to readers that it is not constant. – Hulk May 25 '23 at 14:20
  • 1
    It might seem to work most of the time, but there is **no guarantee**. You are setting yourself up for hard-to-diagnose bugs in production, if you ignore that fact. – Thomas May 25 '23 at 14:26