前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >java设计模式(2)-单例设计模式

java设计模式(2)-单例设计模式

作者头像
爱敲代码的猫
发布2019-10-17 01:03:13
3660
发布2019-10-17 01:03:13
举报
文章被收录于专栏:爱敲代码的猫爱敲代码的猫

上一篇推文写了工厂方法模式,包括简单工厂模式、多工厂模式、静态工厂模式、抽象工厂模式,这篇推文记录一下单例设计模式

单例设计模式

在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在。这样的模式有几个好处:某些类创建比较频繁,对于一些大型的对象,这是一笔很大的系统开销。省去了new操作符,降低了系统内存的使用频率,减轻GC压力。有些类如交易所的核心交易引擎,控制着交易流程,如果该类可以创建多个的话,系统完全乱了。所以只有使用单例模式,才能保证核心交易服务器独立控制整个流程。

饿汗式

先创建实例,用静态方法调用优点:实现起来简单,没有多线程同步问题。

缺点:当类Singleton被加载的时候,会初始化static的instance,静态变量被创建并分配内存空间,从这以后,这个static的instance对象便一直占着这段内存(即便你还没有用到这个实例),当类被卸载时,静态变量被摧毁,并释放所占有的内存,因此在某些特定条件下会耗费内存。

代码语言:javascript
复制
public class SingleTon {

    //在类的内部创建一个类的实例
    private static SingleTon instance = new SingleTon();

    //私有构造方法,防止被实例化
    private SingleTon() {
    }

    //如果该对象被用于序列化,可以保证对象在序列化前后保持一致
    public Object readResolve() {
        return instance;
    }

    //私有化此对象,通过公共的方法来调用,此公共方法只能用类来条用(static修饰),同时类的实例也应为static
    public static SingleTon getInstance(){
        return instance;
    }
}

class Test{

    public static void main (String[] args){
        SingleTon s1 = SingleTon.getInstance();
        SingleTon s2 = SingleTon.getInstance();
        System.out.println(s1 == s2); //true
    }
}

在静态方法创建实例并直接调用如果不是线程同步,在多线程环境下,可能线程1正在创建单例时,线程2判断单例instance为空,就会创建多个实例优点:实现起来比较简单,当类Singleton被加载的时候,静态变量static的instance未被创建并分配内存空间,当getInstance方法第一次被调用时,初始化instance变量,并分配内存,因此在某些特定条件下会节约了内存。

缺点:在多线程环境中,这种实现方法是完全错误的,根本不能保证单例的状态。

代码语言:javascript
复制
public class SingleTon {
    //在类的内部创建一个类的实例
    private static SingleTon instance = null;

    private SingleTon(){}

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

}

class Test{

    public static void main (String[] args){
        SingleTon s1 = SingleTon.getInstance();
        SingleTon s2 = SingleTon.getInstance();
        System.out.println(s1 == s2); //true
    }
}

懒汉式(线程安全)

优点:在多线程情形下,保证了“懒汉模式”的线程安全。

缺点:众所周知在多线程情形下,synchronized 方法通常效率低,显然这不是最佳的实现方案。例如SingleTon实例不为null的情况下,线程同步机制必须等待才能进入if块,而如果存在实例,完全可以跳过等待,直接返回,因为不用进入if块。

代码语言:javascript
复制
public class SingleTon{
    private SingleTon(){}
    private static SingleTon instance = null;
    public static synchronized SingleTon getInstance(){
        if(instance == null)
            instance = new SingleTon();

        return instance;
    }
}

懒汉式(DCL双检查锁机制,线程安全)

代码语言:javascript
复制
public class SingleTon{
    private SingleTon(){}

    private static SingleTon instance = null;
    public static  SingleTon getInstance(){
        // 第一次检查instance是否被实例化出来,如果没有则进入if块
        if(instance == null){
            synchronized (SingleTon.class) {
                // 某个线程取得了类锁,实例化对象前第二次检查instance是否已经被实例化出来,如果没有,才最终实例出对象
                if (instance == null) {
                    instance = new SingleTon();
                }
            }
        }

        return instance;
    }

}

总结

单例模式理解起来简单,但是具体实现起来还是有一定的难度。synchronized关键字锁定的是对象,在用的时候,一定要在恰当的地方使用(注意需要使用锁的对象和过程,可能有的时候并不是整个对象及整个过程都需要锁)

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-03-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 爱敲代码的猫 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 单例设计模式
  • 饿汗式
  • 懒汉式(线程安全)
  • 懒汉式(DCL双检查锁机制,线程安全)
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档