To let multiple threads safely access a shared resource, Java provides synchronization, which restricts access to a critical section of code so only one thread can execute it — and therefore modify the shared state — at any given time.
Key Points: • The synchronized keyword can be applied to a method or a specific block, locking either the enclosing object or an explicitly chosen lock object. • Only one thread can hold a given lock at a time; other threads attempting to enter a synchronized section on the same lock block until it's released. • Keeping the synchronized section as small as possible (just the actual critical code) minimizes contention and improves throughput. • Beyond synchronized, higher-level tools like ReentrantLock, java.util.concurrent collections, or atomic classes offer alternative or more flexible ways to achieve the same safety. • Proper synchronization prevents race conditions, where the final state of shared data depends unpredictably on thread timing.
Example: A shared inventory counter updated by multiple order-processing threads can be protected by wrapping the decrement operation in a synchronized block on the inventory object, ensuring two threads never simultaneously read and decrement the same stale count.
Code Example:
public synchronized void decrementStock(int qty) {
if (stock >= qty) {
stock -= qty;
}
}Interview Tip: A concise interview answer is:
"I'd use synchronization — either a synchronized method or block — around the critical section that touches the shared resource, so only one thread can execute it at a time. That prevents race conditions from multiple threads reading and modifying the same state concurrently."