-1

Consider the following code implementing double check locking using the synchronized keyword in JAVA 8:

private static void redoHeavyInitialisation() {
    if (needToReinitialise()) {
        synchronized (MyClass.class) {
            if (needToReinitialise()) {
                doHeavyInitialisation();
            }
        }
    }
}

The reason double check locking is used is because the initialisation is heavy (hence lazy) AND it can happen more than once (hence singleton pattern can not be used, correct me if I am wrong).

Anyway, first, how do you convert the code above to use Lock from the JAVA concurrent package instead of using synchronized keyword?

Only after that AND optionally, feel free to comment on using Lock or synchronized keyword which one is better.

Remember, this question is not about Lock vs synchronized comparison. Answer attempts without answering the code conversion part will not be picked as accepted answer.

user1589188
  • 5,316
  • 17
  • 67
  • 130
  • Possible duplicate of [Synchronization vs Lock](http://stackoverflow.com/questions/4201713/synchronization-vs-lock) – Erwin Bolwidt Feb 01 '17 at 01:37
  • @ErwinBolwidt Yes if you only focus on the comparison and totally ignore this question asking for an equivalent code conversion, which is the main question. You dont have to comment on the comparison if you dont feel wanting to, but answer the code conversion please. – user1589188 Feb 01 '17 at 01:44
  • You could use singleton. One possible architecture would be creating a Singleton HeavyInitializer class with synchronized methods to initialize and redoInitialization. – Chocksmith Feb 01 '17 at 01:45
  • @Chocksmith I am not aware of a way to use singleton to do re-initialisation because all singleton patterns I know rely on the non-concurrent initialisation of the singleton instance. How do you re-trigger that after the first and only instance was created? – user1589188 Feb 01 '17 at 01:48
  • The HeavyInitializer class must have a static attribute to store the singleton object and also have a synchronized static getInstance() method. It serializes the access to the singleton and to the initialization and re-initialization methods. – Chocksmith Feb 01 '17 at 01:55
  • @Chocksmith Please consider a multi-thread environment (and the reason why synchronized is used). What you said does not solve the issue automatically. – user1589188 Feb 01 '17 at 02:05
  • @user1589188 The accepted answer shows how you can call Lock.acquire and Lock.release to do the equivalent of a `synchronized` block. It's unclear from your question why you are unable to do that yourself. If you have tried and have some particular problem with it, you should post your code and highlight the issue that you are having. – Erwin Bolwidt Feb 01 '17 at 02:12
  • @ErwinBolwidt What you said does not form an answer by itself. You'll need more than that like a try catch block, which is not automatically observable from the question you linked. This already justified this question to be on its own. – user1589188 Feb 01 '17 at 02:18
  • `synchronized` is better than `Lock` in this case, because, just look at it! :) – ZhongYu Feb 01 '17 at 02:26
  • 1
    You shouldn't talk to the people who are trying to help you as if they're filling in for the servant that normally does your homework. – Matt Timmermans Feb 01 '17 at 02:33
  • @user1589188 Apparently, you already knew that (about the try/catch), so why didn't you show what you already know in your question? As I said before: you should show your research, and in the case of a code question, that means that you should include your code and show where you are having a problem, otherwise your question is off-topic for StackOverflow. You can find out more about asking good questions in the [help]. – Erwin Bolwidt Feb 01 '17 at 02:35
  • @ErwinBolwidt I know the answer or not is not relevant in asking the question. Otherwise how could there be self-answered question? A question asked does not only benefit the one who ask but also help the others. – user1589188 Feb 01 '17 at 02:38

3 Answers3

2

Transformation of synchronized blocks to the equivalent block using ReentrantLock is pretty rote.

First you create a lock with the same or similar scope and lifetime as the object you were locking on. Here you are locking on MyClass.class, hence a static lock, so you can map this to a static lock in MyClass, such as MyClass.initLock.

Then just replace each:

synchronized (object) {

with

lock.lock();
try {

and each associated closing brace with

} finally {
  lock.unlock();
}

Putting it all together you have:

private final static ReentrantLock initLock = new ReentrantLock();

private static void redoHeavyInitialisation() {
    if (needToReinitialise()) {
        MyClass.initLock.lock();
        try {
            if (needToReinitialise()) {
                doHeavyInitialisation();
            }
        } finally {
          MyClass.initLock.unlock();
        }
    }
}

Performance-wise there is little daylight between the approaches. They essentially have the same semantics and usually use similar underlying mechanisms. In the past, there have been performance differences - sometimes optimizations have gone in that affect one or the other, so on some JVMs you can find a difference, but the whole point of double checked locking is to avoid taking the lock anyway, so just do what's simplest. You only get the lock for a very small transitory period while the needToReinitialise() method is running, so the locking cost won't have any ongoing impact.

BeeOnRope
  • 60,350
  • 16
  • 207
  • 386
  • Thank you. Almost the best answer. Could you please comment on why it has to be `ReentrantLock` but not the other variants of `Lock` is used? – user1589188 Feb 01 '17 at 02:27
  • `ReentrantLock` is the only directly instantiable implementation of the `Lock` interface that I know of in Java 8. What other implementations are you talking about? @user1589188 – BeeOnRope Feb 01 '17 at 02:29
  • Sorry I meant the lock package. Others like read/write, stamped, locksupport. – user1589188 Feb 01 '17 at 02:33
  • 1
    No idea why you'd use those here. `ReentrantLock` is a direct replacement for `synchronized` and fits your usage. The others are other things entirely, and in the case of "locksupport" not even locks. @user1589188 – BeeOnRope Feb 01 '17 at 02:38
  • _`ReentrantLock` is a direct replacement for synchronized_ fair enough. Its all good with this piece of additional information. – user1589188 Feb 01 '17 at 02:41
0

Consider the following code:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class HeavyInitializer {
static final Logger logger = LoggerFactory.getLogger(HeavyInitializer.class);
static HeavyInitializer singleton;
public static synchronized HeavyInitializer getInstance() {
    if (singleton==null) {
        singleton = new HeavyInitializer();
    }
    return singleton;
}
boolean initialized;
private HeavyInitializer() {
    initialized = false;
}

public synchronized void initialize() {
     if (!initialized) {
         heavyStuffDoneHere();
     }
}
public synchronized void reInitilize() {
    if (needToReinitialise()) {
        heavyStuffDoneHere();
    }
}

private void heavyStuffDoneHere() {
    initialized = true;
}

private boolean needToReinitialise() {
    if (!initialized)
       return false;
    boolean ret = false;
    //Do your check here... and set ret     
    return ret;
}

}

From Oracle's doc:

... then making these methods synchronized has two effects:

  • First, it is not possible for two invocations of synchronized methods on the same object to interleave. When one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object.

  • Second, when a synchronized method exits, it automatically establishes a happens-before relationship with any subsequent invocation of a synchronized method for the same object. This guarantees that changes to the state of the object are visible to all threads.

Trying to use Lock would be trying to reimplement the synchronized block. Not necessary.

Chocksmith
  • 1,188
  • 2
  • 12
  • 40
  • thanks for your effort. I would love to give you score but what you have there uses `synchronized` like the example in my question, which does not answer my question at all. – user1589188 Feb 01 '17 at 02:30
  • 1
    Just trying to contribute and present an alternative architecture. My experience shows that reimplementing synchronized with locks or semaphores will result in difficult bugs to solve in execution time. I would use the synchronized singleton architecture. – Chocksmith Feb 01 '17 at 02:33
-1

Singleton Double checks the lock and prevents singleton object to break using serialization.

package pattern.core.java; import java.io.Serializable;

public class Singleton extends Object implements Serializable {

private static final long serialVersionUID = 1L;
private static Singleton sg;

private Singleton() {
}

public static Singleton getSingletonObj() {
    if (sg == null) {
        synchronized (sg) {
            if (sg == null) {
                sg = new Singleton();
            }
        }
    } 
    return sg;
}


/*
 * this method ensures that new object will not be created for singleton
 * class using serialization and deserialization
 */
protected Object readResolve() {
    return sg;
}

/*
 * @Override protected Object clone() throws CloneNotSupportedException {
 * throw new CloneNotSupportedException(); }
 */

@Override
protected Object clone() throws CloneNotSupportedException {
    return sg;
}

}

Sachin
  • 1