javaconcurrencysingletondouble-checked-locking

java codes that fails double locking checking


Notes: I know that before java 5(given in 2004), double checking lock will fail in java, even you add "volatile" to the "instance" field. and after java 5 the volatile semantics has been right for double checking lock. I also know that without "volatile", double checking lock will fail even after java5, due to out-of-order executing. BUT, My question is : how to write codes to prove that(double checking lock will fail without "volatile")???

I have read lots of articles saying that double checking lock will fail in java, so I think below codes, which try to get a singleton instance of SocketFactory, will fail ( since the "instance" field is not volatile):

  private static SocketFactory instance  = null;
  private static SocketFactory getInstance() {
      if (instance == null) {
         synchronized (SocketFactory.class){
            if (instance == null){
               instance = new SocketFactory(); // line 1
            }
         }
      }
      return instance;
   }

but, the question is , if above code will fail, how can I prove that? I tried to write below codes( I thought, if the line 1 will be re-ordered, the "instance" reference may pointing to a SocketFactory object with the "constructed" field being "false"):

import java.io.*;
import java.nio.*;
import java.nio.file.*;

public class TIJ_doubleCheckingLock {

    static TIJ_doubleCheckingLock instance;

    private Object lock;

    private boolean constructed = false;

    {   
        constructed = false;
    }

    private TIJ_doubleCheckingLock() {
        try{
            Thread.sleep(10000);
        } catch(Exception e) {
        }
        constructed = true;
    }

    static TIJ_doubleCheckingLock getInstance() {
        if (instance == null) {
            synchronized (TIJ_doubleCheckingLock.class) {
                try{
                    Thread.sleep(1000);
                } catch(Exception e) {

                }
                if(instance == null) {
                    instance = new TIJ_doubleCheckingLock();
                }
            }
        }
        return instance;
    }

    public static void main(String args[]) {
        class MyThread extends Thread {
                @Override
                public void run() {

                    TIJ_doubleCheckingLock instance = TIJ_doubleCheckingLock.getInstance();
                    String fileName = "TIJ_doubleCheckingLockResult.txt";
                    java.io.File file = new File(fileName);
                    try {
                        if(!instance.constructed) {
                            java.nio.file.Files.write(Paths.get(file.toURI()), (instance.constructed+"").
                                    getBytes("utf-8"), StandardOpenOption.CREATE, StandardOpenOption.APPEND);
                        }
                    } catch (Exception e) {
                    }
                }

        }

        Thread firstThread = new MyThread();
        firstThread.start();

        try{
            Thread.sleep(5000);
        } catch(Exception e) {}


        for(int i=0;i<10;i++) {
            Thread thread = new MyThread(); 
            thread.start();
        }
    }
}

but I never see a "false" in the txt file. so how can I prove that the double checking lock will fail?


Solution

  • Double checked locking was broken in Java. Your code works fine with Java 5 and onwards. The JVM since got a new memory model.

    Also your code needs the volatile keyword.

    private static volatile SocketFactory instance;