The synchronized keyword in Java

Declaring a method as synchronized

To the programmer, declaring a method as synchronized is essentially the same as wrapping the method body in a synchronized (this) block. So the above Counter class could be written:

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

If we declare a static method as synchronized, then the lock is obtained on the corresponding Class object.

Generally, which alternative used in cases such as this is a matter of style, although at the bytecode level there is actually a very slight difference1. However, there are some potential problems with declaring methods as synchronized:

Bloch and Gafter (2005) provide a fun example of the first problem, which I have adapted here. The Processor class below is intended to process in a separate thread jobs added via its addJob() method. The requestStopAndWaitToFinish() method is designed to tell the thread to stop running and prevent further jobs from being added. Both methods are synchronized, so that in theory a call to addJob() can't be run while the stop request method is running and waiting for the thread to finish:

public class Processor extends Thread {
  private volatile boolean stopRequested;

  public synchronized void requestStopAndWaitToFinish() {
    stopRequested = true;
    join();
  }

  public synchronized void addJob(Object job) {
    if (!stopRequested) {
      // ... interesting code
    }
  }

  public void run() {
    while (!stopRequested) {
      // .. process jobs using more interesting code
    }
  }
}

What's not obviously wrong with this code at first sight is that the call to join() inside requestStopAndWaitToFinish() actually gives up the lock– via a call to Object.wait()– while waiting for the thread to finish, so that another thread can step in and run addJob()! The moral of the story is that you should always be very sure that nothing else is going to interfere with the lock acquired by a synchronized method, or else declare a separate, private Object to synchronize on. (But conversely, if you are sure that nothing else will interfere, it may not desirable to create lots of other spurious objects just for the purpose of synchronization.)

On the next page, we look at the volatile keyword in Java, which is to some extent a "lighter" version of synchronization.


Notes:
1. When synchronized is used in a method declaration, it is marked as a flag on the method. The compiler does not insert instructions to acquire and release the lock; instead, the VM sees the flag on the method declaration and knows to "automatically" acquire and release the lock on method entry and exit. Now, is it worth shaving two bytecodes from a method? Usually not, but consider, for example, that the Hotspot compiler uses the number of bytecodes in a method as a metric for deciding whether or not to inline it.