33
21

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

singletonの色んな実装方法を集めました。

Last updated at Posted at 2017-11-17

Singleton実装種類

典型

もっとも典型的な書き方ですが、Non Thread Safeです。

public class Singleton1 {
    private static Singleton1 singleton = null;

    private Singleton1() {
        try {
            Thread.sleep(2 * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static Singleton1 getInstance() {
        if (singleton == null) {
            singleton = new Singleton1();
        }
        return singleton;
    }
}
Non-Thread-Safe
ExecutorService executor = Executors.newFixedThreadPool(2);

Future<Singleton1> f1 = executor.submit(Singleton1::getInstance);
Future<Singleton1> f2 = executor.submit(Singleton1::getInstance);

Singleton1 s1 = f1.get();
Singleton1 s2 = f2.get();

System.out.println(s1);
System.out.println(s2);
System.out.println(s1 == s2);
異なるID
design.singleton.Singleton1@7ba4f24f
design.singleton.Singleton1@3b9a45b3
false

synchronized

典型的な書き方にsynchronizedを追加して、Thread Safeにします。
が、インスタンス生成後もsynchronizedのロックは解除できないので、性能面の懸念があります。

synchronized
public class Singleton2 {
    private static Singleton2 singleton = null;

    private Singleton2() {
        try {
            Thread.sleep(2 * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static synchronized Singleton2 getInstance() {
        if (singleton == null) {
            singleton = new Singleton2();
        }
        return singleton;
    }
}

Double Check Lock

synchronizedの上に、もう一回Checkを追加することで、
synchronizedロックを回避したものです。

が、実は原子性の問題により、Thread Safeではないです!
詳細まで把握してないですが、new Singleton3()が幾つかに分解して実行されるからです。

DCL
public class Singleton3 {
    private static Singleton3 singleton = null;

    private Singleton3() {
        try {
            Thread.sleep(2 * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static Singleton3 getInstance() {
        // 原子性によって、スレッドセーフではない
        if (singleton == null) {
            synchronized (Singleton3.class) {
                if (singleton == null) {
                    singleton = new Singleton3();
                }
            }
        }
        return singleton;
    }
}

volatile + DCL

volatileを使い、原始性を保証して、Double Check Lockを実装したものです。

volatile
public class Singleton4 {
    private static volatile Singleton4 singleton = null;

    private Singleton4() {
        try {
            Thread.sleep(2 * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static Singleton4 getInstance() {
        // Volatileによって、原子性が保証される
        if (singleton == null) {
            synchronized (Singleton4.class) {
                if (singleton == null) {
                    singleton = new Singleton4();
                }
            }
        }

        return singleton;
    }
}

static fianl

クラスローダのおかげで、Thread Safeになり、書き方もシンプル。
が、リソースが無駄に使われる可能性がある。

static_final
public class Singleton5 {

    private static final Singleton5 singleton = new Singleton5();

    private Singleton5() {}

    public static Singleton5 getInstance() {
        return singleton;
    }
}

Holder

static finalでThread Safeにしながら、遅延生成してリソースも無駄にしない実装です。

Holder
public class Singleton6 {

    private static class SingletonHolder {
        private static final Singleton6 singleton = new Singleton6();
        private SingletonHolder() { }
    }

    private Singleton6() {
    }

    public static Singleton6 getInstance() {
        return SingletonHolder.singleton;
    }
}

enum

enumを利用する。
が、リソースが無駄に使われる可能性がある。

enum
public enum Singleton7 {
    SINGLETON;
}

本質は、static finalとあまり変わらないですが、publicであること。
public static final Singleton7 SINGLETON = new Singleton7();

まとめ

実装方法 無駄リソース スレッド安全 スレッドパフォーマンス顧慮
典型 NO NO -
synchronized NO YES NO
Double Check Lock NO NO -
volatile + DCL NO YES YES
static fianl YES YES YES
Holder NO YES YES
enum YES YES YES

総合的にみると、volatile + DCLHolderがベストかな!

33
21
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
33
21

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?