java设计模式-单例模式

来源:互联网 发布:大鱼海棠 楸 知乎 编辑:程序博客网 时间:2024/06/05 20:06

对一些重要资源的访问, 有时需要实例创建只有一份, 那么实例创建就需要用到单例模式 .


恶汉式:

在类初始化时候就加载了对象, 可以不用考虑多线程问题 .
缺点 : 如果对象创建比较耗资源, 提前加载会耗费性能 .

/** * 恶汉式 * @author 张延 *  */public class SingleInstance {    // 类初始化就加载这个对象, JVM初始化是线程安全的    private static SingleInstance singleInstance = new SingleInstance();    // 私有化构造器    private SingleInstance(){};    // 提供一个公共的获取对象方法    public static SingleInstance getInstance() {        return singleInstance;    }}

懒汉式:

  • 不加锁
    多线程情况会出现问题, 可能会导致两份实例创建
/** * 懒汉式 * @author 张延 *  */public class SingleInstance {    private static SingleInstance singleInstance = null;    private SingleInstance(){};    public static SingleInstance getInstance() {        if(singleInstance == null) {            singleInstance = new SingleInstance();        }        return singleInstance;    }}
  • 加锁方式
    针对上面不安全方式改进, 但是这种synchronized修饰方法会导致性能降低, 因为getInstance是一个频繁被使用方法,
/** * 加锁的懒汉式 * @author 张延 *  */public class SingleInstance1 {    private static SingleInstance1 singleInstance = null;    private SingleInstance1() {};    // 在方法上加锁,限制多个线程同时进入,导致实例化不是一份    public synchronized static SingleInstance1 getInstance() {         if(singleInstance == null) {             singleInstance = new SingleInstance1();         }         return singleInstance;    }}
  • 双重锁检查
    将锁的粒度降低, 多线程都可以进去判断”null == singleInstance” , 只有当没有实例创建才会进入同步快, 再次检查是否创建, 如果没有创建,才会创建这个实例 .
/** * 双重锁检查的懒汉式 * @author 张延 * */public class SingleInstance2 {    private volatile static SingleInstance2 singleInstance = null;    private SingleInstance2() {};    public static SingleInstance2 getInstance() {        // 多线程可以进来判断是否为null,只有当没有创建实例,才会进入同步代码快        if(singleInstance == null) {            // 将锁的粒度降低,            synchronized (SingleInstance2.class) {                if(singleInstance == null) {                    singleInstance = new SingleInstance2();                }            }        }        return singleInstance;    }}

静态内部类方式:

基本具备很多优点 , 高校调用 , 延时加载 , 线程安全
SingleInstance类被加载, 但是instance不会被初始化, 可以做到延时加载, 只有当主动获取实例变量, 才会显示加载类, 因为JVM是天然线程安全的, 不会加载两份, 所以实例化instance很耗资源, 应该让他延时加载 .

public class SingleInstance {    // 初始化SingleInstance的时候,内部类InnerClass不会被加载,只有在被主动使用才会加载    private static class InnerClass {        private static SingleInstance singleInstance = new SingleInstance();    }    private SingleInstance() {};    public static SingleInstance getInstance() {        // 当这里主动使用, 才会加载InnerClass,才会创建SingleInstance实例        return InnerClass.singleInstance;    }}

总结:

饿汉式 : 线程安全 , 调用效率高 , 但是不能延时加载
懒汉式(加锁) : 线程安全 , 调用效率不高 , 但是可以延时加载
静态内部类 : 线程安全 , 调用效率高 , 并且还可以延时加载

0 0
原创粉丝点击