This is perhaps an out of the ordinary question in the day-to-day development office environment, but not so in an interview situation. In the process we consult summary references and then finally authoritative references.
Summary Reference: Java Pocket Guide
The Pocket Guide will help you say that with the synchronized keyword one can:
- 1. Limit access to sections of code, such as blocks and methods, to a single thread
- 2. Control access to resources shared by multiple threads
The first point defines mutual exclusion. The second point hints at why one would want to have the capability mentioned by the first.
Authoritative Reference: Effective Java, Second Edition
With this reference your answer will become more accurate and comprehensive, you will be able to say that with the synchronized keyword one can:
- Prevent safety failures by enforcing mutual exclusion, that is, enforce synchronized access to shared mutable data
- Prevent liveness failures by ensuring that inter-thread communication takes place so that one thread is able to see the most recently written shared mutable data value(s).
- In some cases synchronize unnecessarily using the keyword, since mutual exclusion, enforced by locking, has a performance penatly. It may be that one only needs to prevent liveness failures, and so only need the inter-thread communication benefits, and here the volatile keyword may be more appropriate (especially when using atomic variables).
- In some cases synchronize unnecessarily using the keyword, when one could have used classes from java.util.concurrent.atomic, such as AtomicLong.
Über Authoritative Reference: Java Concurrency in Action
If you where to quote Goetz et. al. directly, quoting from Section 2.3.1, Intristic Locks, you will say:
Java provides a built-in locking mechanism for enforcing atomicity: the synchronized block…A synchronized block has two parts: a reference to an object that will serve as the lock, and a block of code to be guarded by that lock. Every Java object can implicitly act as a lock for purposes of synchronization; these built-in locks are called intrinsic locks or monitor locks.
This reference adds the following regarding the semantics of the sychronized keyword, or implicitly, the topic of intrinsic locks in Java:
- Intrinsic locks are automatically acquired by the executing thread when entering asynchronized block and released when exiting the said block
- Intrinsic locks are mutually exclusive and by this we mean that at most one thread can hold any given lock at a given time
- Threads that want to acquire a lock already held by another thread must block, i.e. wait, potentially indefinitely
- The mutual exclusivity offered by a synchronized block means that multiple statements can be executed atomically
- Overzealous use of synchronized blocks can easily lead to “unacceptable poor responsiveness“
- Intrinsic locks are reentrant, in other words, threads encountering locks they already own themselves will reenter the said synchronize block, i.e. locks are acquired on a per thread basis and not per invocation basis
- When making compund actions on mutable state variables atomic, as required for thread safety, make sure variables guarded by a lock are guarded by the same lock everywhere the said variable is accessed
- When a class has invariants involving more than one mutable state variable, all of the variables involved in the invariant must be guarded by the same lock
- It is vital that maintainers can easily identify which single lock is being used to guard a given shared, mutable variable