ProgrammingBackend Developer

How does the synchronized mechanism work in Java? When to apply it, and what pitfalls exist when synchronizing access to resources?

Pass interviews with Hintsage AI assistant

Answer.

Background of the question:

Since the emergence of Java, developers have faced the issue of concurrent access to shared resources. To address this, high-level synchronization primitives were introduced, the main one being the synchronized key modifier.

Problem:

Without synchronization in multithreaded applications, shared resources can be corrupted: a data race occurs, and the object's state becomes unpredictable.

Solution:

synchronized allows organizing a monitor for a method or a block of code, providing access to only one thread at a time to the critical section. Thread synchronization can be implemented at the method or block level.

Example of locking an object:

public class Counter { private int count = 0; public synchronized void increment() { count++; } public int getCount() { return count; } }

Blocks can also be synchronized:

public void safeIncrement() { synchronized(this) { count++; } }

Key features:

  • Synchronization at the method level is equivalent to synchronization at the this level
  • For static methods, synchronization is per the class object
  • It is essential to minimize the critical section's scope

Trick Questions.

What is the difference between a synchronized method and a synchronized block?

The synchronized method locks the entire method for the current object (this) or the class (if the method is static). The block allows synchronizing only the required piece of code and selecting any object for locking.

Can two different threads simultaneously enter two different synchronized methods of the same object?

No, if the methods are synchronized on the same monitor (this). If different monitors are used, then yes.

Does the synchronized modifier affect the visibility of variables between threads?

Yes, entering a synchronized block flushes the thread caches and updates variable values (happens-before relationship).

Common Mistakes and Anti-patterns

  • Synchronizing on too "broad" an object (e.g., on String or class objects)
  • Long execution of code inside a synchronized block
  • Mixing access to a single resource through synchronized blocks and unsynchronized sections

Real-life Example

Negative Case

A developer synchronizes static methods of a class on an instance object, which does not guarantee correctness when used across different instances.

Pros:

  • Simple implementation

Cons:

  • Unexpected data races between threads
  • Hard-to-detect bugs

Positive Case

All methods using a shared resource are synchronized on a single monitor object, and the critical section's scope is minimal.

Pros:

  • Threads work with consistent data
  • Minimal blocking

Cons:

  • More difficult to maintain and analyze deadlocks, especially with a large number of synchronized objects