import java.util.*;
import java.util.concurrent.Semaphore;

public class Singleton {

    private static volatile Singleton singleton;
    static Semaphore semaphore;

    private Singleton() { semaphore = new Semaphore(1); }

    public  Singleton getInstance() throws InterruptedException{
        // TODO: 3/29/20 Synchronize this
        semaphore.acquire();
        if(singleton == null) {
            System.out.println("created singleton");
            singleton = new Singleton();
        }
        semaphore.release();
        return singleton;
    }

    public static void main(String[] args) {
        // TODO: 3/29/20 Simulate the scenario when multiple threads call the method getInstance
        List<Thread> list = new ArrayList<>();
        Singleton s = new Singleton();
        for(int i = 0; i < 20; i++) {
            list.add(new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        s.getInstance();
                    }
                    catch (InterruptedException e) {
                        
                    }
                }
            }));
        }
        for(int i = 0; i < 20; i++) {
            list.get(i).start();
        }
        for(int i = 0; i < 20; i++) {
            try {
                list.get(i).join();
            }
            catch (InterruptedException e) {
                System.out.println(e);
            }
        }

    }

}