If I have a variable from which multiple threads read and only one thread writes, do I need to have a lock around that variable? Would it crash if one thread tries to read and the other thread tries to write at the same time?
(definition) Definition: A parallel memory model in which multiple processors can read simultaneously from a single memory location, and multiple processors can write simultaneously to a single memory location. Also known as CRCW.
What is concurrency? Concurrency is the ability to run several programs or several parts of a program in parallel. If a time consuming task can be performed asynchronously or in parallel, this improves the throughput and the interactivity of the program.
The main way we can avoid such concurrency issues and build reliable code is to work with immutable objects. This is because their state cannot be modified by the interference of multiple threads. However, we can't always work with immutable objects.
Concurrency is the ability to run several or multi programs or applications in parallel. The backbone of Java concurrency is threads (a lightweight process, which has its own files and stacks and can access the shared data from other threads in the same process).
The simple answer is yes, you need synchronization.
If you ever write to a field and read it from anywhere else without some form of synchronization, your program can see inconsistent state and is likely wrong. Your program will not crash but can see either the old or new or (in the case of longs and doubles) half old and half new data.
When I say "some form of synchronization" though, I more precisely mean something that creates a "happens-before" relationship (aka memory barrier) between the write and read locations. Synchronization or java.util.concurrent.lock classes are the most obvious way to create such a thing, but all of the concurrent collections typically also provide similar guarantees (check the javadoc to be sure). For example, doing a put and take on a concurrent queue will create a happens-before relationship.
Marking a field as volatile prevents you from seeing inconsistent references (long-tearing) and guarantees that all threads will "see" a write. But volatile fields writes/reads cannot be combined with other operations in larger atomic units. The Atomic classes handle common combo ops like compare-and-set or read-and-increment. Synchronization or other java.util.concurrent synchronizers (CyclicBarrier, etc) or locks should be used for larger areas of exclusivity.
Departing from the simple yes, there are cases that are more "no, if you really know what you're doing". Two examples:
1) The special case of a field that is final and written ONLY during construction. One example of that is when you populate a pre-computed cache (think of a Map where keys are well-known values and values are pre-computed derived values). If you build that in a field prior to construction and the field is final and you never write to it later, the end of the constructor performs "final field freeze" and subsequent reads DO NOT need to synchronize.
2) The case of the "racy single check" pattern which is covered in Effective Java. The canonical example is in java.lang.String.hashCode(). String has a hash field that is lazily computed the first time you call hashCode() and cached into the local field, which is NOT synchronized. Basically, multiple threads may race to compute this value and set over other threads, but because it is guarded by a well-known sentinel (0) and always computes the identical value (so we don't care which thread "wins" or whether multiple do), this actually is guaranteed to be ok.
A longer reference (written by me): http://refcardz.dzone.com/refcardz/core-java-concurrency
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