Java设计模式

Java 编程学习--常见的单例设计模式

2019-12-13  本文已影响0人  再让你三行代码

这篇文章是我在黑马程序员参加培训时,老师讲到Java常见的四种单例设计模式,这两天在网盘里整理时发现了当时做的这份笔记,认真整理了一下分享给大家。


适合功能场景

配置文件读写对象, 数据库连接池, Spring的 IOC容器 ApplicationContext, Windows的任务管理/回收站等

主要特点

单例类只能实例化一次;
提供唯一全局访问入口来获取该实例;

饿汉式单例 Eager loading(立即加载方式)

项目启动时类被加载, 对象与之同时实例化
除非项目重启否者对象不会有变化, 也就是线程安全的

public class EagerSingleton implements Serializable {
    private static final long serialVersionUID = 7073777279565036708L;

    private static volatile EagerSingleton instance = new EagerSingleton();

    /**
     * 为了防止通过反射机制实例化构造方法抛异常
     * */
    private EagerSingleton() {
        if(instance != null){
            throw new RuntimeException("不允许被反射实例化");
        }
    }

    public static EagerSingleton getInstance() {
        return instance;
    }

    /**
     * readResolve方法的作用为防止序列化单例时破坏唯一实例的规则
     * */
    private Object readResolve() throws ObjectStreamException {
        return instance;
    }

}

public class App {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(() -> {
                System.out.println("EagerSingleton > " + Thread.currentThread().getName() + " > " + EagerSingleton.getInstance());
            });
            thread.start();
        }
    }

}

EagerSingleton > Thread-0 > com.test.web4.singleton.EagerSingleton@6a3289ca
EagerSingleton > Thread-1 > com.test.web4.singleton.EagerSingleton@6a3289ca
EagerSingleton > Thread-2 > com.test.web4.singleton.EagerSingleton@6a3289ca
EagerSingleton > Thread-3 > com.test.web4.singleton.EagerSingleton@6a3289ca
EagerSingleton > Thread-4 > com.test.web4.singleton.EagerSingleton@6a3289ca
EagerSingleton > Thread-5 > com.test.web4.singleton.EagerSingleton@6a3289ca
EagerSingleton > Thread-6 > com.test.web4.singleton.EagerSingleton@6a3289ca
EagerSingleton > Thread-7 > com.test.web4.singleton.EagerSingleton@6a3289ca
EagerSingleton > Thread-8 > com.test.web4.singleton.EagerSingleton@6a3289ca
EagerSingleton > Thread-9 > com.test.web4.singleton.EagerSingleton@6a3289ca

懒汉式单例 Lazy Loading(延迟加载方式)

类被加载时, 对象不被实例化. 此单例是通过类提供的全局访问入口来获取对象或实例化首个实例后获取对象
==注: 懒汉式由于有线程安全问题必须做双重检查并加锁==

public final class LazySingleton implements Serializable {
    private static final long serialVersionUID = -5683703520820349246L;

    private static volatile LazySingleton instance = null;

    /**
     * 为了防止通过反射机制实例化构造方法抛异常
     * */
    private LazySingleton() {
        if (instance != null) {
            throw new RuntimeException("不允许被反射实例化");
        }
    }

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

    /**
     * readResolve方法的作用为防止序列化单例时破坏唯一实例的规则
     * */
    private Object readResolve() throws ObjectStreamException {
        return instance;
    }

}

public class App {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(() -> {
                System.out.println("LazySingleton > " + Thread.currentThread().getName() + " > " + LazySingleton.getInstance());
            });
            thread.start();
        }
    }

}

LazySingleton > Thread-0 > com.test.web4.singleton.LazySingleton@5e5035fb
LazySingleton > Thread-1 > com.test.web4.singleton.LazySingleton@5e5035fb
LazySingleton > Thread-2 > com.test.web4.singleton.LazySingleton@5e5035fb
LazySingleton > Thread-3 > com.test.web4.singleton.LazySingleton@5e5035fb
LazySingleton > Thread-4 > com.test.web4.singleton.LazySingleton@5e5035fb
LazySingleton > Thread-5 > com.test.web4.singleton.LazySingleton@5e5035fb
LazySingleton > Thread-6 > com.test.web4.singleton.LazySingleton@5e5035fb
LazySingleton > Thread-7 > com.test.web4.singleton.LazySingleton@5e5035fb
LazySingleton > Thread-8 > com.test.web4.singleton.LazySingleton@5e5035fb
LazySingleton > Thread-9 > com.test.web4.singleton.LazySingleton@5e5035fb

枚举单例

Java虚拟机默认防止了枚举类型的序列化和反射破坏, 所以构造方法无需抛异常以及无需加 readResolve方法

public enum EnumSingleton {
    INSTENCE;

    private EnumSingleton() {}

    private Object data;

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public static EnumSingleton getInstance() {
        return INSTENCE;
    }

}

public class App {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(() -> {
                System.out.println("EnumSingleton > " + Thread.currentThread().getName() + " > " + EnumSingleton.getInstance());
            });
            thread.start();
        }
    }

}

EnumSingleton > Thread-0 > INSTENCE
EnumSingleton > Thread-1 > INSTENCE
EnumSingleton > Thread-2 > INSTENCE
EnumSingleton > Thread-3 > INSTENCE
EnumSingleton > Thread-4 > INSTENCE
EnumSingleton > Thread-5 > INSTENCE
EnumSingleton > Thread-6 > INSTENCE
EnumSingleton > Thread-7 > INSTENCE
EnumSingleton > Thread-8 > INSTENCE
EnumSingleton > Thread-9 > INSTENCE

ConcurrentHashMap容器单例

通过 ConcurrentHashMap管理多个对象, 虽然它本身是线程安全的但获取实例的方法不是, 所以需要使用同步锁

public class ContainerSingleton {
    private ContainerSingleton() {}

    private static Map<String,Object> ioc = new ConcurrentHashMap<>();

    public static Object getBean(final String className) {
        if (className != null && !"".equals(className)) {
            synchronized (className) {
                if (ioc.containsKey(className)) {
                    return ioc.get(className);
                }
                Object obj = null;
                try {
                    obj = Class.forName(className).newInstance();
                    ioc.put(className,obj);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return obj;
            }
        }
        return null;
    }

}

/**
* 此测试类需通过反射机制实例化, 所以必须有无参构造方法
* */
public class TestA {
    private Integer id;
    private String name;

    public TestA() {}

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

public class App {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(() -> {
                System.out.println("ContainerSingleton > " + Thread.currentThread().getName() +
                        " > " + ContainerSingleton.getBean("com.test.web4.singleton.TestA"));
            });
            thread.start();
        }
    }

}

ContainerSingleton > Thread-0 > com.test.web4.singleton.TestA@6d559005
ContainerSingleton > Thread-1 > com.test.web4.singleton.TestA@6d559005
ContainerSingleton > Thread-2 > com.test.web4.singleton.TestA@6d559005
ContainerSingleton > Thread-3 > com.test.web4.singleton.TestA@6d559005
ContainerSingleton > Thread-4 > com.test.web4.singleton.TestA@6d559005
ContainerSingleton > Thread-5 > com.test.web4.singleton.TestA@6d559005
ContainerSingleton > Thread-6 > com.test.web4.singleton.TestA@6d559005
ContainerSingleton > Thread-7 > com.test.web4.singleton.TestA@6d559005
ContainerSingleton > Thread-8 > com.test.web4.singleton.TestA@6d559005
ContainerSingleton > Thread-9 > com.test.web4.singleton.TestA@6d559005

Java自学资料整理:

Java基础教程(编程就像打字一样简单) 资料网盘 提取码:78lv

上一篇下一篇

猜你喜欢

热点阅读