zoukankan      html  css  js  c++  java
  • 单例模式(Singleton Pattern)

    单例模式使用场景很多:session,上下文,数据库连接池,全局配置文件等。

    单例模式的写法也有很多种:

    1.饿汉式 : 加载类的时候,就创建对象。线程安全。但有的时候不一定用得着,可能造成内存浪费。

    package stu.design.singleton.hungry;
    
    public class HungrySingleton {
    
        private static final HungrySingleton hungrySingleton = new HungrySingleton();
    
        private HungrySingleton() {
        }
    
        public static HungrySingleton getInstance() {
            return hungrySingleton;
        }
    }
    View Code

    1.2 静态饿汉式:在类中的静态属性中创建类。

    package stu.design.singleton.hungry;
    
    public class HungryStaticSingleton {
    
        private static final HungryStaticSingleton hungrySingleton;
    
        static {
            hungrySingleton = new HungryStaticSingleton();
        }
    
        private HungryStaticSingleton() {
        }
    
        public static HungryStaticSingleton getInstance() {
            return hungrySingleton;
        }
    }
    View Code

    2.懒汉式: 第一次调用getInstance()方法的时候再创建。 容易造成线程安全问题。

    package stu.design.singleton.lazy;
    
    public class LazySimpleSingleton {
    
        private static LazySimpleSingleton lazy = null;
    
        private LazySimpleSingleton() {
        }
    
        public synchronized static LazySimpleSingleton getInstance() {
            if (null == lazy) {
                lazy = new LazySimpleSingleton();
            }
            return lazy;
        }
    }
    View Code

    2.2 双重检测懒汉式:懒汉式中,使用synchronized 锁加到方法上,影响性能。 可以加锁到执行代码间。

    package stu.design.singleton.lazy;
    
    public class LazyDoubleCheckSingleton {
    
        private volatile static LazyDoubleCheckSingleton lazy = null;
    
        private LazyDoubleCheckSingleton() {
        }
    
        public static LazyDoubleCheckSingleton getInstance() {
            if (null == lazy) {
                synchronized (LazyDoubleCheckSingleton.class) {
                    if (null == lazy) {
                        lazy = new LazyDoubleCheckSingleton();
                    }
                }
            }
            return lazy;
        }
    }
    View Code

    2.3 内部静态类的单例模式: 内部静态类在类加载的时候,JVM底层实现了实例化。其可能会被序列化破坏,需实现 Serializable 的 readResolve()方法

    package stu.design.singleton.lazy;
    
    import java.io.Serializable;
    
    // static inner class
    public class LazyInnerClassSingleton implements Serializable {
    
        // 防止反射破坏单例模式
        private LazyInnerClassSingleton() {
            if (null != LazyHolder.lazy) {
                throw new RuntimeException("not allow many instance");
            }
        }
    
        public static final LazyInnerClassSingleton getInstance() {
            return LazyHolder.lazy;
        }
    
        private static class LazyHolder {
            private static final LazyInnerClassSingleton lazy = new LazyInnerClassSingleton();
        }
    
        // 防止序列化破坏单例模式
        private Object readResolve(){
            return LazyHolder.lazy;
        }
    }
    View Code

    3.枚举实现: 枚举的优势在于JVM底层避免了枚举类型被反射,序列化破坏其单例性。

    package stu.design.singleton.register;
    
    public enum EnumSingleton {
        INSTANCE;
    
        // 实例化的对象
        private Object data;
    
        public Object getData() {
            return data;
        }
    
        public void setData(Object data) {
            this.data = data;
        }
    
        public static EnumSingleton getInstance() {
            return INSTANCE;
        }
    }
    View Code

    3.2 容器实现: 容器中线程不安全,容器使用个的是每个线程作为主键。 所以是每个线程是安全,但线程间不是同一单例。

    package stu.design.singleton.register;
    
    import java.util.Map;
    import java.util.concurrent.ConcurrentHashMap;
    
    public class ContainerSingleton {
        
        private ContainerSingleton() {
        }
    
        private static Map<String, Object> ioc = new ConcurrentHashMap<>();
    
        public static Object getBean(String className) {
            synchronized (ioc) {
                if (!ioc.containsKey(className)) {
                    Object obj = null;
                    try {
                        obj = Class.forName(className).newInstance();
                        ioc.put(className, obj);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    return obj;
                }
                return ioc.get(className);
            }
        }
    }
    View Code

    4.伪线程安全实现:每个线程的单例是安全的,但线程与线程间的不是安全的。

    package stu.design.singleton.threadlocal;
    
    /**
     * 伪线程安全
     * 使用threadLocal,多数据源动态切换
     * data source route
     */
    public class ThreadLocalSingleton {
    
        private static final ThreadLocal<ThreadLocalSingleton> threadLocalInstance = new ThreadLocal<ThreadLocalSingleton>() {
            @Override
            protected ThreadLocalSingleton initialValue() {
                return new ThreadLocalSingleton();
            }
        };
    
        public static ThreadLocalSingleton getInstance() {
            return threadLocalInstance.get();
        }
    }
    View Code

    推荐使用枚举实现。

    欢迎指正。

  • 相关阅读:
    Android Studio 单刷《第一行代码》系列 05 —— Fragment 基础
    Android Studio 单刷《第一行代码》系列 04 —— Activity 相关
    Android Studio 单刷《第一行代码》系列 03 —— Activity 基础
    Android Studio 单刷《第一行代码》系列 02 —— 日志工具 LogCat
    Android Studio 单刷《第一行代码》系列 01 —— 第一战 HelloWorld
    IDEA 内网手动添加oracle,mysql等数据源,以及server returns invalid timezone错误配置
    eclipse maven设置
    IntelliJ IDE 常用配置
    eclipse maven 常见问题解决方案
    Maven 安装和配置
  • 原文地址:https://www.cnblogs.com/Payne-SeediqBale/p/10958884.html
Copyright © 2011-2022 走看看