设计模式-单例模式

    类和对象的关系很容易理解,对象就是类的一个具体实例。我们每个类可以创建多个对象,这些对象是相互独立不同的对象。但是有的时候我们的某个类只希望创建一个对象,不需要创建多个对象。比如框架加载在读取配置文件的时候,读取并保存配置文件信息的对象我们没必要创建多个,只要有一个对象读取到配置信息并保存在对象中,然后所有要使用到配置信息的地方都使用这个对象就可以了。如果有很多个对象读出来的配置是一样一样的,那么是完全没必要的,除了浪费资源。再比如我们的工具类、线程池、缓存、日志对象等等。对于这样的一些类,我们只希望永远有且只有一个对象的实例,那么我们就可以使用单例模式去创建实例。单例顾名思义就是只有一个实例,对于单例模式我们通常又有两种单例模式,分别是饿汉模式和懒汉模式。
1、饿汉单例:在类初始化的时候就加载
//饿汉单例模式
public class Singleton1 {
 // 定义一个单例类的实例对象instance,同时实例初始化,一定要用static修饰
 private static Singleton1 instance = new Singleton1();

 // 构造器是私有的,只能在该类中被使用,注意使用private修饰
 private Singleton1() {
 }

 // 对外提供一个访问获取该对象实例的方法,返回之前已经创建的实例
 public static Singleton1 getInstance() {
  return instance;
 }
}

2、懒汉单例:只有在第一次用到的时候才会去加载
//懒汉单例模式
public class Singleton2 {
 // 定义一个单例类的实例对象instance,但是暂时不创建该对象的实例,一定要用static修饰
 private static Singleton2 instance = null;

 // 构造器是私有的,只能在该类中被使用,注意使用private修饰
 private Singleton2() {
 }

 // 对外提供一个访问获取该对象实例的方法,返回上面定义的实例对象
 public static Singleton2 getInstance() {
  // 因为上面的实例对象在类初始化的时候并没有创建,所以在此处判断如果还没有实例化,就创建一个实例
  if (instance == null) {
   instance = new Singleton2();
  }
  // 返回实例的时候,一定是不为空的
  return instance;
 }
}
饿汉模式是线程安全的,而懒汉模式因为在用到的时候才去加载,所以可能在多线程中同事请求创建实例,所以这就导致懒汉模式加载是线程不安全的。因此我们一般在使用懒汉模式的时候,会加入多线程控制,以多线程下也是正常的单例模式。代码写法一般有两种,一种是在方法上加入synchronized,另一种是将创建代码放在synchronized包裹的代码块中:
// 加入synchronized目的是防止多线程下创建多个实例,那样其实就不是单例了
public static synchronized Singleton2 getInstance() {
 if (instance == null) {
  instance = new Singleton2();
 }
 return instance;
}
对于上面两种单例模式都有各自的缺陷,恶汉模式没有延迟加载,导致的结果可能是在初始化的时候,消耗太多资源。懒汉模式虽然延迟加载了,但是为了线程安全导致效率降低。

3、饿汉改版延迟加载实例:使用静态内部类延迟加载
//内部类获得饿汉单例模式
public class Singleton3 {
 // 定义一个内部类,该内部类持有一个外部类的实例对象
 private static class SingletonHolder {
  private final static Singleton3 INSTANCE = new Singleton3();
 }

 // 构造器是私有的,只能在该类中被使用,注意使用private修饰
 private Singleton3() {
 }

 // 对外提供一个访问获取该对象实例的方法
 public static Singleton3 getInstance() {
  // 通过内部类对象获取单例实例对象
  Singleton3 instance = SingletonHolder.INSTANCE;
  return instance;
 }
}
这样做的目的是在类初始化的时候并不加载内部类对象,因为内部类没有被使用所以是不会加载的。当获取单例实例的时候,内部类会去实例化一个单例对象,然后返回给调运放,这样既保证了线程安全,也保证了延迟加载。如果在不要求延迟加载的情况下,建议使用第一种饿汉模式,如果在要求延迟加载的情况下,建议使用第三种以保证效率。

    单例模式还有两种创建方式,一种是通过枚举,一种 是通过 volatile 关键字双重校验,不过个人觉得很少有人用这两种方式。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值