单例模式的五种写法

本文详细介绍了单例模式的懒汉式和饿汉式两种实现方式,并对比了它们的特点及适用场景。通过五种不同的实现代码示例,展示了如何在多线程环境下确保实例的唯一性和线程安全性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景知识

谈到单例模式时总是有懒汉式和饿汉式的说法,我们先来看看懒汉式和饿汉式的特点

懒汉式:
1.在创建实例对象时不加上synchronized则会导致对对象的访问不是线程安全的
2.懒汉式是延时加载,需要的时候在创建对象
3.懒汉式需要关注线程同步的问题,优点是只在需要的时候创建加载对象

饿汉式:
1.线程安全的,在类创建的同时就已经创建好一个静态的对象供系统使用,以后不在改变
2.饿汉式在加载类时创建实例
3.饿汉式无需关注多线程问题,写法简单明了。但如果是一个工厂模式、缓存了很多实例、就需要考虑效率问题,因为这个类一加载会把所有实例一起创建。

实现方式

第一种(懒汉式,线程不安全)

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

问题:能实现懒加载,但多线程时会出现问题

第二种(懒汉式,线程安全)

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

问题:能实现懒加载,线程也是安全的,但是对所有的操作进行加锁操作,效率低

第三种(饿汉式)

public class Singleton {
    private static Singleton instance = new Singleton();
    private Singleton (){}
    public static Singleton getInstance() {
        return instance;
    }
}

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

问题:实现差别表面看着挺大,其实本质都是一样,加载的时候就创建对象,涉及效率问题

第四种(静态内部类)

/**  
     * 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例  
     * 没有绑定关系,而且只有被调用到才会装载,从而实现了延迟加载  
 */
public class Singleton {
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();// 静态初始化器,由JVM来保证线程安全
    }
    private Singleton (){}
    public static final Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

问题:能实现懒加载,线程也是安全的,类被加载后如果没有调用getInstance()方法那么instance不会被加载,能达到一个懒加载的目的

第五种(双重校验)

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

问题:能实现懒加载,线程也是安全的,大家比较常用的一种方式

总结

第一和第二种不建议使用。个人推荐第三种和第四种方式,简单易懂,而且在JVM层实现了线程安全(如果不是多个类加载器环境),一般的情况下第三种方式就能满足需求,只有在要明确实现懒加载效果时才会使用第四种方式,如果有其他特殊需求建议第五种。

参考:

http://cantellow.iteye.com/blog/838473
http://blog.youkuaiyun.com/abc19900828/article/details/39479377

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值