I used to believe that any variable that is shared between two threads, can be cached thread-locally and should be declared as volatile. But that belief has been challenged recently by a teammate. We are trying to figure out whether volatile is required in the following case or not.

Now my contention is that, it is possible that the Worker (child) thread could have cached the variable "value" of the Worker object within the thread and updated just it's copy while setting the value to 1. In such a case, main thread may not see the updated value.

But my teammate believes that since the access to "value" is happening through an object (worker), therefore for both the threads to see different values, it could only be possible if both the threads were maintaining separate copies of "worker" object itself (which would further mean that creation of a thread involves creating a deep copy of all the shared objects).

Now I know that that can't be true, for it would be highly inefficient for each thread to maintain wholly different copies of all shared objects. So hence, I am in serious doubt. Does doing a "worker.value" in the main thread reference a different memory location than doing a "this.value" in the child thread? Will the child (Worker) thread cache "value"?

You shouldn't describe this as "thread-locally", as this will mislead readers into thinking that you are talking about ThreadLocals.
–
Stephen CJun 15 '12 at 16:10

You are right Stephen. I thought of the same just immediately after posting the question. I have posted a question on Stack Overflow for the first time in my life, so please bear with me. :)
–
Abhay DangJun 15 '12 at 16:16

2 Answers
2

Now my contention is that, it is possible that the Worker (child) thread could have cached the variable "value" of the Worker object thread-locally and updated just it's copy while setting the value to 1. In such a case, main thread may not see the updated value.

You are correct. Even though you are both dealing with the same Worker instance, there is no guarantee that the cached memory version of the Worker's fields have been synchronized between the various different thread memory caches.

The value field must be marked as volatile to guarantee that other threads will see the value = 1; update to the value field.

But my teammate believes that since the access to "value" is happening through an object (worker), therefore for both the threads to see different values, it could only be possible if both the threads were maintaining separate copies of "worker" object itself...

No, this is not correct. The tricky part about thread memory revolves around processor memory caches. Without a memory barrier that is imposed by volatile, a process is completely free to cache memory. So even though both threads would be working with the same instance of the Worker, they may have a locally cached copy of the memory associated with Worker.

Thread architectures get much of their speed because they are working with separate high-speed processor-local memory as opposed to always referencing central storage.

+1, I'd also play it safe and use an AtomicInteger rather than a volatile int.
–
sjrJun 15 '12 at 16:02

An AtomicInteger is just a wrapper around a volatile int so not much savings there -- especially if it is changed once.
–
GrayJun 15 '12 at 16:05

1

There are cognitive savings: no need to dwell on whether volatile is required. Just use AtomicInteger and get on with life ;)
–
sjrJun 15 '12 at 16:06

2

Another way to think about this... Because worker could be changing value at any time, independently and inconsistently with the other thread's view of it, the memory model allowsworker to have it's own view of value as a performance optimization. You need volatile to explicitly say that you intend for two threads to have a consistent view of this variable. That changes what is allowed- now every read needs to synchronize memory first.
–
Chris ShainJun 15 '12 at 16:14

Thanks a lot Gray and Chris for explaining things. I guess the fact that I got so horribly confused is a wake-up call for me to read in depth about how Java manages concurrency. :)
–
Abhay DangJun 15 '12 at 16:23

But my teammate believes that since the access to "value" is happening through an object (worker), therefore for both the threads to see different values, it could only be possible if both the threads were maintaining separate copies of "worker" object itself (which would further mean that creation of a thread involves creating a deep copy of all the shared objects).

What your coworker does not realize is that values of instance variables (any variables for that matter) can be cached temporarily in machine registers, or in the processor's first or second-level memory caches. The Java Language Specification explicitly says that two threads won't necessarily see the same values for the same variable unless they have taken the appropriate steps.

There is a whole section of the JLS that deals with this issue: JLS 17.4. I recommend that both you and your co-worker read this and 17.5 and 17.6 as well if you are going to debate how Java behaves in this area. Or you could read the last chapter of "Java Concurrency in Practice" by Brian Goetz et al which is rather more easy to read than the JLS.

I'd recommend that you and your co-worker don't rely on your intuition about threading ought to work. Read the specs. Some aspects of thread behaviour are not intuitive ... though there are good reasons way they are the way they are,