美文网首页
设计模式总结(一) 单例模式

设计模式总结(一) 单例模式

作者: 文泰ChrisTwain | 来源:发表于2020-12-13 10:53 被阅读0次

0.简介:单例类表示仅允许一个实例存在

(1)注意点:
  1. 单例模式构造方法的访问修饰符为private
  2. 双重检查锁模式注意添加volatile关键字;
  3. Singleton成员变量和单例获取方法都应该为static
(2)适用场合
  • 需要频繁的进行创建和销毁的对象;
  • 创建对象时耗时多或耗费资源多,又经常用到的对象,如频繁访问数据库或文件的对象;
  • 工具类对象。
(3)总结

单例模式有五种写法:懒汉、饿汉、双重检验锁、静态内部类、枚举;
单线程场景使用懒汉式第一种写法,多线程场景可使用饿汉式,希望懒加载(lazy initialization)则使用静态内部类或者双重检查锁,如果涉及到反序列化创建对象时应使用枚举方式来实现单例,或为Singleton类增加如下readResolve()方法。

private Object readResolve() throws ObjectStreamException {
    return INSTANCE;
}

1.枚举单例

通过Singleton.INSTANCE来访问实例。创建枚举默认就是线程安全的,而且还能防止反序列化导致重新创建新的对象。《Effective Java》中讲到枚举是实现单例的最佳方式,建议在实际项目中单例以枚举方式实现。《Java并发编程实践》中推荐使用静态内部类单例模式。

public enum Singleton {

    INSTANCE;
    
    public void myMethod() {
        // doSomething;
    }
}

2.静态内部类单例

类的静态属性只会在第一次加载类时初始化,JVM帮助我们保证了线程的安全性,在类进行初始化时,别的线程无法进入。静态内部类方式在Singleton类被装载时并不会立即实例化,而是在需要实例化时,调用getInstance方法,才会装载SingletonInstance类,从而完成Singleton的实例化。

优点:线程安全,懒加载加载,效率高。

public class Singleton {

    private Singleton (){} 

    private static class SingletonHolder {  
        private static final Singleton INSTANCE = new Singleton();  
    }
 
    public static final Singleton getInstance() {  
        return SingletonHolder.INSTANCE; 
    }  
}
public class Singleton {

    private Singleton() {}

    private static class SingletonInstance {
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance() {
        return SingletonInstance.INSTANCE;
    }
}

3.双重检查锁 + volatile:线程安全;延迟加载;效率较高

public class Singleton {

    private static volatile Singleton singleton;

    private Singleton() {}

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

4.饿汉式:类加载时就完成实例化(类加载过程JVM会自动加锁,因此保证了单例特性),避免了线程同步问题,但没有达到懒加载效果

 
public class Singleton{
    
    // 静态常量
    private static final Singleton instance = new Singleton(); //类加载时就初始化
    
    private Singleton(){}
 
    public static Singleton getInstance(){
        return instance;
    }
}
public class Singleton {

    private static Singleton instance;

    // 静态代码块
    static {
        instance = new Singleton();
    }

    private Singleton() {}

    public static Singleton getInstance() {
        return instance;
    }
}

5.懒汉式

(1)线程不安全方式:适用于单线程,多线程场景下可能导致不同线程获取到不同对象的情况(单线程适用)

public class Singleton {
    
    private static Singleton instance = null;
    private Singleton (){}  // 构造方法私有化,外界不能new对象

    public static Singleton getInstance() {
     if (instance == null) {
         instance = new Singleton();
     }
     return instance;
    }
}

(2)线程安全方式,同步方法:每个线程在想获得类实例的时候,执行getInstance()方法都需要进行同步(效率低)

public class Singleton {

    private static Singleton singleton;

    private Singleton() {}

    public static synchronized Singleton getInstance() {
        if (singleton == null) {
            singleton = new Singleton();
        }
        return singleton;
    }
}

(3)线程安全方式,同步代码块:若两个线程都已经通过判空,则将产生两个对象(有风险)

public class Singleton {

    private static Singleton singleton;

    private Singleton() {}

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

6.容器单例:管理单例对象的容器

public class ContainerSingleton {

    private ContainerSingleton() {}

    private static Map<String, Object> singletonMap = new HashMap<String, Object>();

    // 多线程场景可能存入多个key相同但值不同的数据,换成hashtable对性能损耗严重,频繁存取数据不合适。ConcurrentHashMap待分析 
    public static void putInstance(String key, Object instance) {
        if (!TextUtils.isEmpty(key) && instance != null) {
            synchronized (singletonMap) {
                if (!singletonMap.containsKey(key)) {
                    singletonMap.put(key, instance);
                }
            }
        }
    }

    public static Object getInstance(String key) {
        return singletonMap.get(key);
    }
}

HashMap不是线程安全,若希望线程安全,即不存在不同线程取到的对象不是同一个,在putInstance方法上加同步锁或者同步锁HashMap。改成HashTable也能保证线程安全,但会影响性能,频繁取值的时候都会有同步锁

p.s. 懒汉式与饿汉式取名由来:把对象比喻为食物。懒:表示等到肚子饿了才去准备食物;饿:表示提前准备好食物,饿了直接吃即可。

参考:单例设计模式之容器单例

相关文章

  • 单例模式

    单例设计模式是几种设计模式中比较容易理解的,手写单例模式也是面试频繁问到的。下面总结一下单例模式的几种写法: //...

  • 基础-单例模式

    单例模式总结-Python实现 面试里每次问设计模式,必问单例模式 来自《Python设计模式》(第2版) 1.理...

  • 单例模式Java篇

    单例设计模式- 饿汉式 单例设计模式 - 懒汉式 单例设计模式 - 懒汉式 - 多线程并发 单例设计模式 - 懒汉...

  • 设计模式 - 单例模式

    设计模式 - 单例模式 什么是单例模式 单例模式属于创建型模式,是设计模式中比较简单的模式。在单例模式中,单一的类...

  • 2018-04-08php实战设计模式

    一、单例模式 单例模式是最经典的设计模式之一,到底什么是单例?单例模式适用场景是什么?单例模式如何设计?php中单...

  • python中OOP的单例

    目录 单例设计模式 __new__ 方法 Python 中的单例 01. 单例设计模式 设计模式设计模式 是 前人...

  • 单例

    目标 单例设计模式 __new__ 方法 Python 中的单例 01. 单例设计模式 设计模式设计模式 是 前人...

  • 单例模式

    JAVA设计模式之单例模式 十种常用的设计模式 概念: java中单例模式是一种常见的设计模式,单例模式的写法...

  • 设计模式

    常用的设计模式有,单例设计模式、观察者设计模式、工厂设计模式、装饰设计模式、代理设计模式,模板设计模式等等。 单例...

  • 设计模式之单例模式

    单例设计模式全解析 在学习设计模式时,单例设计模式应该是学习的第一个设计模式,单例设计模式也是“公认”最简单的设计...

网友评论

      本文标题:设计模式总结(一) 单例模式

      本文链接:https://www.haomeiwen.com/subject/gibugktx.html