Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are objects visible to all threads, while a reading thread might not see a value written by another thread on a timely basis?

From java in a nutshell

In Java, all Java application threads in a process have their own stacks (and local variables) but share a single heap. This makes it very easy to share objects between threads, as all that is required is to pass a reference from one thread to another.

This leads to a general design principle of Java—that objects are visible by default. If I have a reference to an object, I can copy it and hand it off to another thread with no restrictions. A Java reference is essentially a typed pointer to a location in memory—and threads share the same address space, so visible by default is a natural model.

From Java Concurrency in Practice

Visibility is subtle because the things that can go wrong are so counterintuitive. In a single-threaded environment, if you write a value to a variable and later read that variable with no intervening writes, you can expect to get the same value back. This seems only natural. It may be hard to accept at first, but when the reads and writes occur in different threads, this is simply not the case. In general, there is no guarantee that the reading thread will see a value written by another thread on a timely basis, or even at all. In order to ensure visibility of memory writes across threads, you must use synchronization.

When a thread reads a variable without synchronization, it may see a stale value.

So why does Java in a Nutshell says objects are visible to all threads, while Java Concurrency in Practice says no guarantee that a reading thread sees a value written by another thread on a timely basis? They don't seem consistent.

Thanks.


1 Answers

"So why does Java in a Nutshell says objects are visible to all threads" --> As your quote says, in Java objects are allocated on the heap. A 'global' heap available for the entire JVM. Whereas in other languages (e.g. C++) objects can also be allocated on a stack. Objects on a heap can be passed to other threads, using different stacks. Objects on a stack can only be used on the thread using the same stack, as the stack's content will change beyond control of another thread.

"while Java Concurrency in Practice says no guarantee that a reading thread sees a value written by another thread on a timely basis?" -> This is another issue, as this is about values of memory locations. Though they are reachable compilers and CPUs try to optimize reading from or writing to this memory locations and will heavily cache the value by assuming "I'm the only one reading and writing to this memory location". So if one thread modifies a memory location's value the other thread does not know it has changed and will not read it new. This makes the program much faster. By declaring a variable volatile you are telling the compiler that another thread may change the value at will and the compiler will use this to create code that doesn't cache the value.

Finally, multithreading is much more difficult than adding volatile, or using synchronized, one really needs to dive into the topic of the issues you will encounter when using multiple threads.

like image 167
M. le Rutte Avatar answered Sep 21 '25 06:09

M. le Rutte