Home  Synchronization and concurrency  wait/notify  final  volatile  synchronized keyword  Java threading  Deadlock (and avoiding it)  Java 5: ConcurrentHashMap  Atomic variables  Explicit locks  Queues  Semaphores  CountDownLatch  CyclicBarrier

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:

  • You generally don't get "private" control of the lock: any code that can see the class in question is free to synchronize on– or worse, release the lock on– that object (of course, that's also true of explicitly synchronizing on this or X.class).
  • It's easier for somebody reading the code to "forget" which object is actually being synchronized on (class or instance).
  • Declaring a method as synchronized means that you are committing to your class using a particular locking mechanism. If a more effective locking mechanism comes along (as has happened in Java 5), you can't use it without changing the definition of your API. Generally speaking, it's usually better not to expose to outside classes implementational details that you don't need to; declaring a method as synchronized may well be doing just that.

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.

Article written by Neil Coffey (@BitterCoffey).

Software

 LetterMeister (word puzzle game for iPhone)
 Currency Quoter (currency converter/predictor)
 French Vocab Games for iPhone/iPad
 Vocabularium: create Spanish vocab podcasts


Java programming articles and tutorials on this site are written by Neil Coffey (@BitterCoffey). Suggestions are always welcome if you wish to suggest topics for Java tutorials or programming articles, or if you simply have a programming question that you would like to see answered on this site. Most topics will be considered. But in particular, the site aims to provide tutorials and information on topics that aren't well covered elsewhere, or on Java performance information that is poorly described or understood. Suggestions may be made via the Javamex blog (see the site's front page for details).
Copyright © Neil Coffey 2014. All rights reserved.