I have a question regarding synchronization of code that is executed by several threads:
As far as I know each thread has its own stack, hence, non-static variables exist in different locations in the memory for each thread (for X threads there are X stacks that include all non-static variables). So why there's a need to synchronize anything?
I mean, if the code that the threads execute includes some class variable v1, then each thread has its own "instance" of v1 (different memory address), and no other thread can "touch" it... isn't it so?
Yes, a thread can modify the stack contents of another thread if they are in the same process. Stack is simply a region of memory in the process's address space and all threads of that process have same access rights to all its memory regions.
Stack Memory and Threads Secondly, it stores local primitives and local object references on the stack. In addition, it's important to realize that every thread, including the main thread, has its own private stack. Therefore, other threads do not share our local variables, which is what makes them thread-safe.
There are two types of thread synchronization mutual exclusive and inter-thread communication.
We can handle this with the help of the synchronized keyword. Making the incr() method synchronized will make sure that only one thread can work with the method the other threads have to wait. Thus making it Thread-Safe.
non-static variables exist in different locations in the memory for each thread
This is not true, so the answer to
if the code that the threads execute includes some class variable v1, then each thread has its own "instance" of v1 (different memory address), and no other thread can "touch" it... isn't it so
is no. Threads can touch object instances allocated and modified by other threads and the burden is on the programmer to ensure this does not affect program correctness.
Class member variables exist in a single place in memory per-class instance, not per thread. It is true that between memory barriers (think the start {
and end }
of synchronized
), that a thread may have a cache of the state of an object, but that is not the same as the language mandating per-thread storage. The "memory for each thread" is its stack which does not contain object members* -- only references to objects.
The best way to think of it is that there is one location on the heap for each object, but that there might be multiple reads&|writes involving that memory location happening at the same time.
I can see how you would come to the conclusions you did if you heard that threads allocate objects in different parts of the heap. Some JVMs have an optimization whereby they do thread-local allocation but that does not prevent other threads from accessing those objects.
Thread-local allocation
If the allocator were truly implemented as shown in Listing 1, the shared heapStart field would quickly become a significant concurrency bottleneck, as every allocation would involve acquiring the lock that guards this field. To avoid this problem, most JVMs use thread-local allocation blocks, where each thread allocates a larger chunk of memory from the heap and services small allocation requests sequentially out of that thread-local block. As a result, the number of times a thread has to acquire the shared heap lock is greatly reduced, improving concurrency.
* - it's possible that JVM optimizations allow some objects to be allocated on the stack.
The stack is thread-safe whereas the heap is not thread-safe unless you synchronized the code. The stack contains local variables and method parameters (primitive and reference) whereas the heap contains objects.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With