欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java实现单例模式的几种方法

程序员文章站 2022-03-07 17:07:06
...

设计模式之单例模式

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

上一篇: WPF动画动态变换

下一篇: WPF之动画