0

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?

Raedwald
  • 46,613
  • 43
  • 151
  • 237
ZhaoGang
  • 4,491
  • 1
  • 27
  • 39
  • You shouldn't be reading articles from the 90's. – Kayaman Jan 15 '16 at 08:10
  • you can refer to http://stackoverflow.com/questions/18093735/double-checked-locking-in-singleton – thinkling Jan 15 '16 at 08:12
  • @ Kayaman so you mean that the double checking lock will NOT fail, without any volatile?? – ZhaoGang Jan 15 '16 at 08:33
  • No, I mean your opening statement of `double checking lock will fail in java` was true in the 90's. I remember those times. You still need the `volatile` keyword to make sure that multiple threads will see the correct value. – Kayaman Jan 15 '16 at 09:28
  • @Kayaman 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")???** – ZhaoGang Jan 15 '16 at 09:44
  • Well, your example won't work. You'd need to run it a few million times at least. I believe this is a bit beyond your skills and I'm too busy to write you an example. Let's hope someone who has the time does it for you. – Kayaman Jan 15 '16 at 09:52
  • so everyone is saying that, but no one can really prove that? – ZhaoGang Jan 15 '16 at 10:00

2 Answers2

1

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;
raupach
  • 3,092
  • 22
  • 30
  • then, what's the difference with or without the volatile keyword? – ZhaoGang Jan 15 '16 at 07:57
  • volatile guarantees that every thread reads the same value and does not cache it. Without it your double checked login might fail. – raupach Jan 15 '16 at 07:58
  • @ raupach you can see that in my codes there is no volatile used. so my code might fail, right? but the question is : how to prove that my code might fail ? – ZhaoGang Jan 15 '16 at 08:02
  • If SocketFactory is immutable your code works, otherwise there is chance your code breaks. – raupach Jan 15 '16 at 08:05
  • That is the problem with multi-threaded applications. Hard to spot the problem. Why don't you read the articles first? – raupach Jan 15 '16 at 08:13
  • yes I have read lots of articles. but without any code really can prove that the double checking lock will fail. – ZhaoGang Jan 15 '16 at 08:31
-1

you need to know the difference of my code in synchronized:

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

/**
 * @author heyunxia (love3400wind@163.com)
 * @version 1.0
 * @since 2016-01-15 下午3:50
 */
public class SocketFactoryTest {

    public static void main(String[] args) {
        SocketFactoryTest test = new SocketFactoryTest();
        test.run();

    }

    private static final int COUNTER = 20;

    CyclicBarrier barrier = new CyclicBarrier(COUNTER);

    public void run(){
        for(int i=0; i<COUNTER; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    SocketFactory.getInstance(barrier);
                }
            }).start();
        }
    }

}


class SocketFactory {
    private static SocketFactory instance = null;

    public static SocketFactory getInstance(CyclicBarrier barrier) {
        if (instance == null) {
            try {
                barrier.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
            synchronized (SocketFactory.class) {
                // option 1
                instance = new SocketFactory();
                System.out.println(Thread.currentThread().getName() + "***");

                /*
                // option 2
                if (instance == null) {
                    System.out.println(Thread.currentThread().getName() + "***");
                    instance = new SocketFactory();
                }else {
                    System.out.println(Thread.currentThread().getName() + "-have already instanced...");
                }*/
            }
        }
        return instance;
    }
}
thinkling
  • 59
  • 2