14

I've come across code like the following several times

class Foo {
   private Object lock = new Object();

   public void doSomething() {
      synchronized(lock) {
         ...

What I'm interested in is why a lock object is created instead of writing synchronized(this)? Is it there to enable sharing the lock? I vaguely remember reading that it is an optimization. Is that true? Also, does it, in some context, make sense to have the lock declared as final?

Karolis Juodelė
  • 3,708
  • 1
  • 19
  • 32

4 Answers4

25
  1. Synchronizing on this is discouraged because if the object itself is used as a lock from the outside it would break the internal synchronization. Also, remember that synchronized methods are also using this as a lock, which may cause an unwanted effect.
  2. Declaring the lock final is recommended to prevent a situation in which a lock object is reassigned inside a synchronized block, thus causing different threads to see different lock objects. See this other question: Locking on a mutable object - Why is it considered a bad practice?
Community
  • 1
  • 1
Tudor
  • 61,523
  • 12
  • 102
  • 142
5

Imagine a scenario where you have thread1 and thread2 access method1, thread3 and thread4 access method2. Synchronizing on this would block thread3 and thread4 if thread1 or thread2 are accessing method1 which should not happen as thread3 and thread4 have nothing to do with method1. An optimization for this is to use two different locks instead of locking on the whole class instance.

Here is a nice paragraph I found on JavaDoc that reflects this:

Synchronized statements are also useful for improving concurrency with fine-grained synchronization. Suppose, for example, class MsLunch has two instance fields, c1 and c2, that are never used together. All updates of these fields must be synchronized, but there's no reason to prevent an update of c1 from being interleaved with an update of c2 — and doing so reduces concurrency by creating unnecessary blocking

GETah
  • 20,922
  • 7
  • 61
  • 103
0

Consider using a lock from the java.util.concurrent package
This may provide more optimized locking, for instance - using a ReadWriteLock will let all readers to access without waiting.

Yair Zaslavsky
  • 4,091
  • 4
  • 20
  • 27
0

Here is the Full working example of "ReentrantReadWriteLock".

 public class DataReader  {
 private static final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
 private static final Lock read = readWriteLock.readLock();
 private static final Lock write = readWriteLock.writeLock();
 public static void loadData() {
  try {
   write.lock();
   loadDataFromTheDB());
  } finally {
   write.unlock();
  }
 }

 public static boolean readData() {
  try {
   read.lock();
   readData();
  } finally {
   read.unlock();
  }
 }

 public static List loadDataFromTheDB() {
     List list = new ArrayList();
  return list;
 }

    public static void readData() throws DataServicesException {
     //Write reading logic
    }
}
ThiefMaster
  • 310,957
  • 84
  • 592
  • 636