单例设计模式的4种创建方式

单例模式的创建方式众多,这里列出4种创建方式,分别是懒汉式、饿汉式、静态内部类和枚举类单例。

下面的demo代码中都模拟了5个线程同时获取单例实例的场景,模拟使用了CountDownLatch来实现。

懒汉式单例创建

/**
 * 懒汉式单例
 */
public class Singleton1 {

    private static Singleton1 singleton1;

    private Singleton1(String name) {
        System.out.println("构造器 Thread Name:" + name);
    }

    public static Singleton1 getInstance(String name) {
        System.out.println("getInstance Thread Name:" + name);
        if(singleton1 == null) {
            System.out.println("check1 getInstance Thread Name:" + name);
            synchronized (Singleton1.class) {
                System.out.println("check2 getInstance Thread Name:" + name);
                if(singleton1 == null) {
                    singleton1 = new Singleton1(name);
                }
            }
        }
        return singleton1;
    }

}

测试

import java.util.concurrent.CountDownLatch;

public class Singleton1Test {

    public static void main(String[] args) throws InterruptedException {
        CountDownLatch c = new CountDownLatch(1);
        CountDownLatch cdl = new CountDownLatch(5);
        for(int i=0; i<5; i++) {
            new Thread(()->{
                try {
                    c.await();
                    Singleton1 instance = Singleton1.getInstance(Thread.currentThread().getName());
                    System.out.println(instance);
                    cdl.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
        Thread.sleep(3000);
        c.countDown();
        cdl.await();
    }
}

输出:

getInstance Thread Name:Thread-0
check1 getInstance Thread Name:Thread-0
check2 getInstance Thread Name:Thread-0
getInstance Thread Name:Thread-4
check1 getInstance Thread Name:Thread-4
getInstance Thread Name:Thread-2
check1 getInstance Thread Name:Thread-2
getInstance Thread Name:Thread-1
check1 getInstance Thread Name:Thread-1
getInstance Thread Name:Thread-3
check1 getInstance Thread Name:Thread-3
构造器 Thread Name:Thread-0
check2 getInstance Thread Name:Thread-3
check2 getInstance Thread Name:Thread-1
check2 getInstance Thread Name:Thread-2
com.my.study.design.test.Singleton1@451ae77f
com.my.study.design.test.Singleton1@451ae77f
com.my.study.design.test.Singleton1@451ae77f
check2 getInstance Thread Name:Thread-4
com.my.study.design.test.Singleton1@451ae77f
com.my.study.design.test.Singleton1@451ae77f

饿汉式

/**
 * 饿汉式单例
 */
public class Singleton2 {

    private static Singleton2 singleton1 = new Singleton2();

    private Singleton2() {
        System.out.println("构造器 初始化");
    }

    public static Singleton2 getInstance(String name) {
        System.out.println("getInstance Thread Name:" + name);
        return singleton1;
    }

}

测试

import java.util.concurrent.CountDownLatch;

public class Singleton2Test {

    public static void main(String[] args) throws InterruptedException {
        CountDownLatch c = new CountDownLatch(1);
        CountDownLatch cdl = new CountDownLatch(5);
        for(int i=0; i<5; i++) {
            new Thread(()->{
                try {
                    c.await();
                    Singleton2 instance = Singleton2.getInstance(Thread.currentThread().getName());
                    System.out.println(instance);
                    cdl.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
        Thread.sleep(3000);
        c.countDown();
        cdl.await();
    }
}

输出:

构造器 初始化
getInstance Thread Name:Thread-1
getInstance Thread Name:Thread-2
getInstance Thread Name:Thread-3
com.my.study.design.test.Singleton2@451ae77f
getInstance Thread Name:Thread-4
com.my.study.design.test.Singleton2@451ae77f
getInstance Thread Name:Thread-0
com.my.study.design.test.Singleton2@451ae77f
com.my.study.design.test.Singleton2@451ae77f
com.my.study.design.test.Singleton2@451ae77f

静态内部类创建单例

/**
 * 静态内部类单例
 */
public class Singleton3 {

    private Singleton3() {
        System.out.println("Singleton3 new Success");
    }

    private static class Singleton3Inner {
        private static final Singleton3 singleton3 = new Singleton3();
    }

    public static Singleton3 getInstance(String name) {
        System.out.println("getInstance Thread Name:" + name );
        return Singleton3Inner.singleton3;
    }

}

测试

import java.util.concurrent.CountDownLatch;

public class Singleton3Test {

    public static void main(String[] args) throws InterruptedException {
        CountDownLatch c = new CountDownLatch(1);
        CountDownLatch cdl = new CountDownLatch(5);
        for(int i=0; i<5; i++) {
            new Thread(()->{
                try {
                    c.await();
                    Singleton3 instance = Singleton3.getInstance(Thread.currentThread().getName());
                    System.out.println(instance);
                    cdl.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
        Thread.sleep(3000);
        c.countDown();
        cdl.await();
    }
}

输出:

getInstance Thread Name:Thread-0
getInstance Thread Name:Thread-3
Singleton3 new Success
com.my.study.design.test.Singleton3@4b79d4e1
com.my.study.design.test.Singleton3@4b79d4e1
getInstance Thread Name:Thread-2
com.my.study.design.test.Singleton3@4b79d4e1
getInstance Thread Name:Thread-4
com.my.study.design.test.Singleton3@4b79d4e1
getInstance Thread Name:Thread-1
com.my.study.design.test.Singleton3@4b79d4e1

枚举单例:

public enum Singleton4 {

    instance;

    public void test(String name) {
        System.out.println("getInstance Thread Name:" + name );
    }
}

测试

import java.util.concurrent.CountDownLatch;

public class Singleton4Test {

    public static void main(String[] args) throws InterruptedException {
        CountDownLatch c = new CountDownLatch(1);
        CountDownLatch cdl = new CountDownLatch(5);
        for(int i=0; i<5; i++) {
            new Thread(()->{
                try {
                    c.await();
                    Singleton4.instance.test(Thread.currentThread().getName());
                    cdl.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
        Thread.sleep(3000);
        c.countDown();
        cdl.await();
    }
}

输出:

getInstance Thread Name:Thread-0
getInstance Thread Name:Thread-4
getInstance Thread Name:Thread-2
getInstance Thread Name:Thread-3
getInstance Thread Name:Thread-1