Java设计模式(1)-单例模式

单例模式(singleton)

singleton是一种创建型模式,指某个类采用singleton模式,则在这个类被创建后,只可能产生一个实例供外部访问,并提供一个全局的访问点。
核心知识点:
1.将采用单例设计模式的类的构造方法私有化(采用private修饰)
2.在其内部产生该类的实例话对象,并将其封装成private static类型
3.定义一个静态方法返回该类的实例

单例模式总体上来说,分为两类:饿汉式和饱汉式(又叫懒汉式)
两种模式的区别在于:是自己被加载时就将自己实例化(饿汉式)还是第一次被引用时才将自己实例化饱汉式(又叫懒汉式)

下面是针对单例模式写的几个实现方式的demo

方式一:
使用饿汉模式,代码如下:

/**
 * 单例模式实现方式一
 * 饿汉式,线程安全,效率低
 * @author liangxin
 *
 */
public class Singleton1 {

    //定义一个私有构造方法
    private Singleton1() {}

    //将自身低一个实例对象设置为一个属性,并加上static和final修饰符
    private static final Singleton1 instance = new Singleton1();

    //静态方法返回该类的实例
    public static Singleton1 getInstance() {
        return instance;
    }
}

优点:写起来比较简单,而且不存在多线程同步问题,避免了synchronized所造成的性能问题;
缺点:当类singleton被加载的时候,会初始化static的instance,静态变量被创建并分配内存空间,从这以后,这个static的instance对象遍一直占着这段内存(即便你还没有用这个实例),当类被卸载时,静态变量被摧毁,并释放所占有的内存,因此在某些特定情况下会耗费内存。

方式二:
使用饱汉模式,代码如下:

/**
 * 方式二
 * 饱汉式,非线程安全
 * @author liangxin
 *
 */
public class Singleton2 {

    //定义私有构造方法(防止通过new Singleton2()去实例化
    private Singleton2() {}

    //定义一个Singleton类型的变量(不初始化,注意这里没有使用final关键字
    private static Singleton2 instance;

    //定义一个静态的方法(调用是在初始化Singleton,但是多线程访问时,可能造成重复初始化问题)
    public static Singleton2 getInstance() {
        if(instance == null)
            instance = new Singleton2();
        return instance;
    }

}

优点:写起来比较简单,当类singleton呗加载的时候,静态变量static的instance违背创建并分配内存空间,当getInstance方法第一次被调用时,初始化instance变量,并分配内存,因此在某些特定情况下会节约内存
缺点:并发环境下很可能出现多个singleton实例,

方式三
是方法二的简单优化,增加对多线程对支持

/**
 * 方式三
 * 饱汉式的优化升级版,饱汉式,线程安全简单实现
 * @author liangxin
 *
 */
public class Singleton3 {
    //定义私有构造方法(防止通过new Singleton2()去实例化
    private Singleton3() {}

    //定义一个Singleton类型的变量(不初始化,注意这里没有使用final关键字)
    private static Singleton3 instance;

    //定义一个静态方法(调用时在初始化singleton,使用synchronized避免多线程访问时,可能造成重复初始化问题
    public static synchronized Singleton3 getInstance() {
        if(instance == null)
            instance = new Singleton3();
        return instance;
    }
}

优点:使用synchronized关键字避免多线程访问时,出现多个singleton实例
缺点:同步方法频繁调用时,效率略低

方式四:
双重锁定,单例模式最佳实现,使用该方式,可使内存占用低,效率高,线程安全,多线程操作原子性

/**
 * 单例模式最佳实现
 * 内存占有低,效率高,线程安全,多线程操作原子性
 * @author liangxin
 *
 */
public class Singleton4 {
    //定义一个私有构造方法
    private Singleton4() {}

    //定义一个静态私有变量(不初始化,不使用final关键字,使用volatile保证了多线程访问时instance变量的可见性,
    //避免了instance初始化时其他比哪里属性还没赋值完时,被另外线程调用
    private static volatile Singleton4 instance;

    //定义一个共有的静态方法,返回该类型实例
    public static Singleton4 getInstance() {
        //对象实例化与否判断(不使用同步代码块,instance不等于null时,直接返回对象,提高运行效率)
        if(instance == null) {
            //同步代码块(对象未初始化时,使用同步代码块,保证多线程访问时对象在第一次创建后,不在重复被创建)
            synchronized(Singleton4.class) {
                //未初始化,则初始化instance变量
                if(instance == null) {
                    instance = new Singleton4();
                }
            }
        }
        return instance;
    }
}

方法四的实现使用了双重锁定,我们在使用该对象时,不用让线程每次都加锁,而只是在实例未被创建的时候在加锁处理,同时也能保证多线程的安全,这种做法被称为Double-CheckLocking(双重锁定)

对于方法四中为何要使用两个为空判断:
对于instance存在的情况,就不会进入该段逻辑,直接返回,OK,这是没问题的,但是当instance为null,并且同时有两个线程调用getInstance()方法时,他们将都可以通过第一重的instance == null判断,然后由于synchronized机制,这两个线程只有一个进入,另一个在外排队等待,必须要其中一个进入并出来之后,另一个才能进去,而如果没有第二重的instance == null判断,则第一个线程次创建了实例,而第二个线程还是可以继续创建新的实例,这样就没有达到单例的目的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值