Search code examples
javamultithreadingcachingmultiprocessing

Multithreading: Threads manipulating different fields of the same object


Say I have a class X with two variables.

class X {
    Integer a;
    Y b;
    Integer c;
}

The class Y

class Y {
    Integer y1;
    String y2;
}

Say, we have 4 threads, T1, T2, T3 and T4.

T1 operates on a, T2 operates on b.y1 (does something like x.getB().setY1()), T3 operates on b.y2, and T4 operates on c.

I won't be reading any of the "deepest" values (a, y1, y2, c) in any thread till all of them are executed (T2 and T3 will do the x.getB() however).

Would I face any of the typical issues associated with multithreading?

My questions

  1. I think I might not face any race condition with respect to a and c, given that they are not read by threads other than "their" thread. Is this reasoning right?
  2. What about x.getB() by T2 and T3?
  3. What about caching by processors in a multi-core environment? Do they cache the entire object? Or do they cache only the field that they modify? Or do they cache the whole thing but update only the field that they changed?
  4. Do they even recognise objects and fields? Or do they just work on chunks of memory? In that case does Java tell them the memory address they would need to cache?

When the processors reconcile their cache with the main memory after the processing is done, do they only update the chunk of memory they changed, or do they overwrite the main memory with the entire block of memory that they cached?

For example, say, initially, both a and c have values a = 1, and c = 1. P1 and P4 cache these values (a=1 and c=1). T1 changes it to a = 2, T4 changes to c = 2.

Now, the values in the cache C1 are a=2, c=1; in C2, a=1, c=2.

So, when writing back to main memory, say P1 finishes first and then updates the main memory. So, now the values are a=2, c=1.

Now, when P4 finishes, does it update the value of only c, because it has modified only c? Or does it simply overwrite the main memory with the value in its cache, making a=1, c=2?

Or do they simply cache the values they will read or write, meaning T1 will never cache the value of c, and T4 will never cache the value of a.


Solution

  • You question touches on a number of interesting topics. I will try to reformulate your questions and answer them in order.

    On your first question: if different threads only modify different objects, can this pose consistency issues?

    You need to make a distinction between modifying an object (or "writing") and making such changes visible to other threads. In the case you present, your various threads deal with the various objects independently from each-other and never need to "read" other objects. So yes, this is fine.

    However, if a thread needs to read the value of a variable which may have been modified by another thread, you need to introduce some synchronization such that the modification to that variable happens before the first thread reads it (synchronized block / access to a volatile variable / semaphores etc). I cannot recommend enough this article Fixing the Java Memory Model.

    On your second question:

    Same answer to your first question: as long as no thread modifies member b of your X instance, there is no cause for concern; both thread T2 and T3 will obtain the same object.

    On your third and fourth question what about cache consistency?

    How the Java Virtual Machine handles memory allocation is a little obscure from a programmer's perspective. What you are concerned about is called false-sharing. The Java virtual machine will make sure that what is stored in memory is consistent with your program. You do not need to worry about a bad cache overwriting changes made by another thread.

    However, if there is enough contention on the members, you may face a performance penalty. Fortunately you can reduce this impact by using the @Contended annotation on the members that pose problems to indicate to the Java Virtual Machine that they should be allocated on different cache lines.