设计模式之单例模式

Java中单例模式定义:“一个类有且仅有一个实例,并且自行实例化向整个系统提供。”

饿汉式:类加载的时候就实例化,并且创建单例对象。

//饿汉式 :类加载的时候就实例化,并且创建单例对象。
public class Hungry {

    public Hungry() {
        System.out.println(Thread.currentThread().getName()+"ok");
    }

    private static final Hungry HUNGRY = new Hungry();

    public static Hungry getInstance() {
        return HUNGRY;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                Hungry.getInstance();
            }).start();
        }
    }
}

懒汉式,双重检测锁模式的懒汉式单例,DCL模式

//懒汉式
public class LazyMan {

    public LazyMan() {
        System.out.println(Thread.currentThread().getName()+"ok");
    }

    private volatile static LazyMan lazyMan;

    //双重检测锁模式的懒汉式单例,DCL模式
    public static LazyMan getInstance() {
        if(lazyMan == null) {
            synchronized (LazyMan.class) {
                if(lazyMan == null) {
                    lazyMan = new LazyMan();//不是原子性操作
                    /**
                     * 不是原子性操作有三步操作
                     * 1、分配内存空间
                     * 2、执行构造方法,初始化对象
                     * 3、把这个对象指向这个空间
                     *
                     * 可能发生执行重排
                     * 比如本来我们期望是 123
                     * 结果走成 132
                     * 解决方法:volatile关键字
                     */
                }
            }
        }
        return lazyMan;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                LazyMan.getInstance();
            }).start();
        }
    }
}

注意:反射可以破坏单例,枚举类实现单例可以防止反射破坏单例

一定程度上,解决反射破坏单例

//懒汉式
public class LazyMan {

    private static boolean xy = false;

    public LazyMan() {
        synchronized(LazyMan.class) {
            if(xy == false) {
                xy = true;
            }else {
                throw new RuntimeException("不要试图用反射破坏单例");
            }
/*            if(lazyMan != null) {
                throw new RuntimeException("不要试图用反射破坏单例");
            }*/
        }
    }

    private volatile static LazyMan lazyMan;

    //双重检测锁模式的懒汉式单例,DCL模式
    public static LazyMan getInstance() {
        if(lazyMan == null) {
            synchronized (LazyMan.class) {
                if(lazyMan == null) {
                    lazyMan = new LazyMan();//不是原子性操作
                    /**
                     * 不是原子性操作有三步操作
                     * 1、分配内存空间
                     * 2、执行构造方法,初始化对象
                     * 3、把这个对象指向这个空间
                     *
                     * 可能发生执行重排
                     * 比如本来我们期望是 123
                     * 结果走成 132
                     */
                }
            }
        }
        return lazyMan;
    }

    public static void main(String[] args) throws Exception {
/*        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                LazyMan.getInstance();
            }).start();
        }*/
        Constructor<LazyMan> constructor = LazyMan.class.getDeclaredConstructor();
        constructor.setAccessible(true);
        LazyMan lazyMan1 = constructor.newInstance(null);
        //LazyMan lazyMan1 = LazyMan.getInstance();
        LazyMan lazyMan2 = constructor.newInstance(null);
        System.out.println(lazyMan1);
        System.out.println(lazyMan2);
    }
}

静态内部类

//静态内部类
public class Holder {
    private Holder() {}

    public static Holder getInstance() {
        return InnerClass.HOLDER;
    }

    public static class InnerClass {
        private static final Holder HOLDER = new Holder();
    }
}

枚举类实现单例

public class User {
    //私有化构造函数
    private User(){ }
 
    //定义一个静态枚举类
    static enum SingletonEnum{
        //创建一个枚举对象,该对象天生为单例
        INSTANCE;
        private User user;
        //私有化枚举的构造函数
        private SingletonEnum(){
            user=new User();
        }
        public User getInstance(){
            return user;
        }
    }
 
    //对外暴露一个获取User对象的静态方法
    public static User getInstance(){
        return SingletonEnum.INSTANCE.getInstance();
    }
}

class Test {
    public static void main(String [] args){
        System.out.println(User.getInstance());
        System.out.println(User.getInstance());
        System.out.println(User.getInstance()==User.getInstance());
    }
}

Java实现单例模式的几种方法,每种方法各有优劣势,最为安全的个人觉得是枚举类实现单例模式,但是本人日常编码比较少接触到。目前能力有限,文章内容深度可能有限,请多见谅,多指教。
希望能帮助到大家。
最后希望大家有错请指点,本人为小白。在博客为了记录自己的学习历程。感谢!!!