定义一个线程执行器
/** * @description: 执行线程 * @author: lmc * @create: 2019-04-03 08:56 **/ public class ExectorThread implements Runnable { public void run() { LazySimpleSingleton lazySimpleSingleton=LazySimpleSingleton.getInstance(); System.out.println("线程"+Thread.currentThread().getName()+"lazySimpleSingleton"+lazySimpleSingleton); } }测试代码
/** * @description: 简单懒汉式单例测试 * @author: lmc * @create: 2019-04-03 09:10 **/ public class LazySimpleSingletonTest { public static void main(String[] args){ for (int i = 0; i <10; i++) { Thread thread= new Thread(new ExectorThread()); thread.start(); } } }测试结果
可以看到,10个线程获取的对象都是同一个实例。
懒汉式单例之静态内部类单例静态内部类单例在外部类调用获取实例方法的时候才会初始化实例对象,静态内部类在类加载的时候并不会初始化,只有在创建内部类对象或者,内部类对象静态成员被第一次引用的时候才会初始化对象。然而,对于静态内部类单例来说,我们永远不会主动的去创建内部类对象。
/** * @description: 懒汉式静态内部类单例 * @author: lmc * @create: 2019-04-03 11:28 **/ public class LazyInnerClassSingleton implements Serializable { //私有化构造方法 private LazyInnerClassSingleton(){ if(Holder.lazy != null){//只能调用一次构造创建实例 throw new RuntimeException("静态内部类单例,不允许创建多个实例"); } } public static final LazyInnerClassSingleton getInstance(){ return Holder.lazy; } /** * @description:静态内部类初始化外部类成员变量 * @date 2019/5/25 22:11 * @author lmc */ private static class Holder { private final static LazyInnerClassSingleton lazy=new LazyInnerClassSingleton(); } /** * @description: 重写readResolve方法,防止序列化破坏单例 * @return java.lang.Object * @date 2019/5/25 22:12 * @author lmc */ private Object readResolve(){ return Holder.lazy; } }上面的代码中,内部类Holder的静态成员变量 lazy是 final static修饰,无论是创建内部类对象,初始化lazy还是调用静态属性lazy引用初始化都之后初始化一次。并且LazyInnerClassSingleton单例类只能被内部类实例化一次。
测试代码
/** * @description: 内部类懒汉式单例测试 * @author: lmc * @create: 2019-04-03 09:10 **/ public class LazyInnerClassSingletonTest { public static void main(String[] args){ for (int i = 0; i <10 ; i++) { Thread thread= new Thread(new Runnable() { @Override public void run() { LazyInnerClassSingleton lazyInnerClassSingleton = LazyInnerClassSingleton.getInstance(); System.out.println("线程"+Thread.currentThread().getName()+"lazyInnerClassSingleton"+lazyInnerClassSingleton); } }); thread.start(); } } }测试结果
如果需要创建很多单例对象,一般用容器式单例管理对象。
虽然 ConcurrentHashMap是线程安全的,但是调用getBean方法不是线程安全的,所有要加synchronized锁。
容器式单例就不写测试结果了。
注册式单例之枚举单例 /** * @description: 枚举单例 * @author: lmc * @create: 2019-04-03 15:31 **/ 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; } }枚举类型重JVM虚拟机底层就帮我们做了防止序列化和反射破坏单例。