一天一个设计模式---单例模式

介绍:从字面上我们就能看出需要实现的功能—保证类只有一个实例,并提供一个访问此实例的方法。

优点:
1. 频繁使用的对象,可以减少创建对象所消耗的时间。
2. new操作次数的减少,对系统内存的使用频率也会减少,从而减轻GC压力,缩短GC停顿时间。

一、懒汉式

简述:懒汉式单例 在使用的时候去判断单例是否已经存在,然后再调用实例或创建实例 在懒汉式中需要考虑并发问题

1. 不使用同步方法

不使用同步方法,在不同情况下是可以实现单例的。但是在高并发的情况下可能会产生多个实例

public class SingletonLazyNoSync {
    private static SingletonLazyNoSync uniqueInstance;

    private SingletonLazyNoSync() {

    }

    // 静态工厂方法
    public static SingletonLazyNoSync getInstance() {
        // 下面是延迟实例化的方法
        if (uniqueInstance == null)
            uniqueInstance = new SingletonLazyNoSync();

        return uniqueInstance;
    }
}

2. 同步代码块

使用同步方法synchronized,能够在多线程中很好的工作,遗憾的是,效率很低

public class SingletonLazySync {
    private static SingletonLazySync uniqueInstance;

    private SingletonLazySync() {}

    public static synchronized SingletonLazySync getInstance() {
        // synchronized防止在多线程的情况下创建时会产生多个对象(但是synchronized会降低性能,同步一个方法能使程序效率下降100倍)
        // 下面是延迟实例化的方法
        if (uniqueInstance == null)
            uniqueInstance = new SingletonLazySync();

        return uniqueInstance;
    }

}

3. 双重检验加锁

使用双重检验加锁,在getInstance方法中减少同步

public class SingletonVolatile {
    // volatile保证在多线程的时候,每个线程能正确的处理这个单例
    private volatile static SingletonVolatile uniqueInstance;

    private SingletonVolatile() {}

    public static SingletonVolatile getInstance() {

        if (uniqueInstance == null)
            synchronized (SingletonVolatile.class) {
                if (uniqueInstance == null)
                    uniqueInstance = new SingletonVolatile();
            }
        return uniqueInstance;
    }
}

二、饿汉式

简述:饿汉就是类一旦加载,就把单例初始化完成,保证getInstance的时候,单例是已经存在的了

1.静态变量

饿汉式提前实例化,但只要我们初始化类SingletonStatic,不管我们是不是调用getInstance()都会存在一个实例在内存中

public class SingletonStatic {
    private SingletonStatic() {}

    private static final SingletonStatic single = new SingletonStatic();

    public static SingletonStatic getInstance() {
        return single;
    }
}

2.静态内部类

内部类式中,实现了延迟加载,当SingletonStaticClass被加载时,其内部类不会被初始化,即SingletonStaticClass被加载到JVM的时候,不会初始化单例类。只有我们调用了getInstance(),才会加载StaticClass创建唯一的实例INSTANCE到内存中.并且也解决了懒汉式中多线程的问题.

ps:这种方法也可能创建多个实例,比如,通过反射机制来加载单例类的私有构造函数。但是,这样的情况极少

public class SingletonStaticClass {

    private static class StaticClass {
        private static final SingletonStaticClass INSTANCE = new SingletonStaticClass();
    }

    private SingletonStaticClass() {}

    public static SingletonStaticClass getInstance() {
        return StaticClass.INSTANCE;
    }
}

三、其它

public enum SingleInstance {
    INSTANCE;
    public void fun1() { 
        // do something
    }
}

ps:最近在《Effective Java》看到的比较新奇的写法,看起来很简单,而且创建枚举是线程安全的,所以这写法也没有并发的问题。


更多模式: 一天一个设计模式—分类与六大原则

更多源码: https://github.com/oDevilo/Java-Base

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值