单例模式

饿汉式(静态常量):

/**
 * 饿汉式(静态常量)
 *
 * 1.构造器私有
 * 2.定义一个静态常量保存一个唯一的实例对象(单例)
 * 3.提供一个静态方法返回单例对象
 */
public class Singleton01 {

    public static final Singleton01 INSTANCE = new Singleton01();

    private Singleton01() {}

    public static Singleton01 getInstance() {
        return INSTANCE;
    }

}

class Test01 {
    public static void main(String[] args) {
        Singleton01 s1 = Singleton01.getInstance();
        Singleton01 s2 = Singleton01.getInstance();
        System.out.println(s1 == s2); // true
    }
}

饿汉式(静态代码块):

/**
 * 饿汉式(静态代码块)
 *
 * 1.构造器私有
 * 2.定义一个静态常量保存一个唯一的实例对象(单例),通过静态代码块初始化单例对象
 * 3.提供一个静态方法返回单例对象
 */
public class Singleton02 {

    public static final Singleton02 INSTANCE;

    static {
        INSTANCE = new Singleton02();
    }

    private Singleton02() {}

    public static Singleton02 getInstance() {
        return INSTANCE;
    }

}

class Test02 {
    public static void main(String[] args) {
        Singleton02 s1 = Singleton02.getInstance();
        Singleton02 s2 = Singleton02.getInstance();
        System.out.println(s1 == s2); // true
    }
}

懒汉式(线程不安全,不推荐这样写):

/**
 * 懒汉式(线程不安全,不推荐这样写)
 *
 * 1.构造器私有
 * 2.定义一个静态变量存储一个单例对象(定义时不初始化该对象)
 * 3.提供一个静态方法返回单例对象,返回前先询问是否有,有则直接返回,没有则创建新的返回
 */
public class Singleton03 {

    public static Singleton03 instance;

    private Singleton03() {}

    public static Singleton03 getInstance() {
        if (instance == null) {
            instance = new Singleton03();
        }
        return instance;
    }

}

class Test03 {
    public static void main(String[] args) {
        Singleton03 s1 = Singleton03.getInstance();
        Singleton03 s2 = Singleton03.getInstance();
        System.out.println(s1 == s2); // true / false
    }
}

懒汉式(线程安全,性能差,不推荐这样写):

/**
 * 懒汉式(线程安全,性能差,不推荐这样写)
 *
 * 1.构造器私有
 * 2.定义一个静态变量存储一个单例对象(定义时不初始化该对象)
 * 3.提供一个静态同步方法返回单例对象,返回前先询问是否有,有则直接返回,没有则创建新的返回
 */
public class Singleton04 {

    public static Singleton04 instance;

    private Singleton04() {}

    public static synchronized Singleton04 getInstance() {
        if (instance == null) {
            instance = new Singleton04();
        }
        return instance;
    }

}

class Test04 {
    public static void main(String[] args) {
        Singleton04 s1 = Singleton04.getInstance();
        Singleton04 s2 = Singleton04.getInstance();
        System.out.println(s1 == s2); // true
    }
}

懒汉式(线程不安全,不推荐这样写):

/**
 * 懒汉式(线程不安全,不推荐这样写)
 *
 * 1.构造器私有
 * 2.定义一个静态变量存储一个单例对象(定义时不初始化该对象)
 * 3.提供一个静态方法返回单例对象,返回前先询问是否有,有则直接返回,没有则创建新的返回
 */
public class Singleton05 {

    public static Singleton05 instance;

    private Singleton05() {}

    public static Singleton05 getInstance() {
        if (instance == null) {
            // 性能得到了优化,但是依然不能保证第一次获取对象的线程安全
            synchronized (Singleton05.class) {
                instance = new Singleton05();
            }
        }
        return instance;
    }

}

class Test05 {
    public static void main(String[] args) {
        Singleton05 s1 = Singleton05.getInstance();
        Singleton05 s2 = Singleton05.getInstance();
        System.out.println(s1 == s2); // true / false
    }
}

懒汉式(线程安全):其实私有化构造器并不保险,存在反射攻击;还可能出现反序列化攻击的风险

/**
 * 懒汉式(线程安全)
 *
 * 1.构造器私有
 * 2.定义一个静态变量(用volatile修饰,保证可见性和禁止指令重排序)存储一个单例对象(定义时不初始化该对象)
 * 3.提供一个静态方法返回单例对象,返回前先询问是否有,有则直接返回,没有则创建新的返回
 */
public class Singleton06 {

    public static volatile Singleton06 instance;

    private Singleton06() {}

    public static Singleton06 getInstance() {
        if (instance == null) {
            synchronized (Singleton06.class) {
                if (instance == null) {
                    instance = new Singleton06();
                }
            }
        }
        return instance;
    }

}

class Test06 {
    public static void main(String[] args) {
        Singleton06 s1 = Singleton06.getInstance();
        Singleton06 s2 = Singleton06.getInstance();
        System.out.println(s1 == s2); // true
    }
}

懒汉式(基于类的初始化实现延迟加载和线程安全的单例设计):存在反射攻击和反序列化攻击的风险

/**
 * 懒汉式(基于类的初始化实现延迟加载和线程安全的单例设计)
 *
 * 1.构造器私有
 * 2.提供一个静态内部类,里面提供一个常量存储一个单例对象
 * 3.提供一个静态方法返回静态内部类中的单例对象
 */
public class Singleton07 {

    /*private static int i = 0;
    private int j = 0;*/

    private Singleton07() {}

    // 静态内部类只有等到需要用到才会加载,在加载过程中JVM会获取一个锁,不会出现线程安全问题,且只加载一次
    /*静态内部类有一个局限性,只能访问外部类静态的变量,非静态的无法访问*/
    private static class Inner {
        private static final Singleton07 INSTANCE = new Singleton07();

        /*private void test() {
            i += 1;
            // j += 1; // 无法访问
        }*/
    }

    public static Singleton07 getInstance() {
        return Inner.INSTANCE;
    }

}

class Test07 {
    public static void main(String[] args) {
        Singleton07 s1 = Singleton07.getInstance();
        Singleton07 s2 = Singleton07.getInstance();
        System.out.println(s1 == s2); // true
    }
}

枚举实现单例:枚举本身已经实现了线程安全

/**
 * 枚举实现单例
 *
 * 枚举实际上是一种多例的模式,如果我们直接定义一个实例就相当于单例了
 */
public enum Singleton08 {
    INSTANCE;

    public Singleton08 getInstance() {
        return INSTANCE;
    }
}

class test08 {

    public static void main(String[] args) {
        Singleton08 s1 = Singleton08.INSTANCE.getInstance();
        Singleton08 s2 = Singleton08.INSTANCE.getInstance();
        System.out.println(s1 == s2); // true
    }

}

 

posted @ 2020-05-15 12:52  糖不甜,盐不咸  阅读(143)  评论(0编辑  收藏  举报