前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【云+社区年度征文】设计模式-单例模式(五种实现方法详解)

【云+社区年度征文】设计模式-单例模式(五种实现方法详解)

原创
作者头像
唔仄lo咚锵
修改2020-11-27 10:54:33
3700
修改2020-11-27 10:54:33
举报

单例模式,属于创建类型的一种常用的软件设计模式。通过单例模式的方法创建的类在当前进程中只有一个实例(根据需要,也有可能一个线程中属于单例,如:仅线程上下文内使用同一个实例)。就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法)。

就是类在内存中只能存在一个实例对象

饿汉式


所谓饿汉式,就是直接创建出类的实例化,然后用private私有化,对外只用静态方法暴露。

静态变量

步骤

1) 构造器私有化

2) 类的内部创建对象

3) 向外暴露一个静态的公共方法

优点

缺点

写法简单,在类装载的时完成实例化,避免了线程同步问题

类装载时完成实例化,没有达到LazyLoading的效果,若该实例从未使用,则会造成内存浪费

代码语言:txt
复制
class Singleton {
	//私有化构造器
	private Singleton() {	
	}
	//内部创建对象实例
	private final static Singleton instance = new Singleton();
	//对外公有的静态方法
	public static Singleton getInstance() {
		return instance;
	}
}

静态代码块

将类的实例化放到静态代码块中的写法,基本同上。

代码语言:txt
复制
class Singleton {  //静态代码块
	//私有化构造器
	private Singleton() {}
	//内部创建对象实例
	private  static Singleton instance;
	static { // 在静态代码块中,创建单例对象
		instance = new Singleton();
	}
	//对外公有的静态方法
	public static Singleton getInstance() {
		return instance;
	}
}

测试代码(后面都可使用这个测试代码,不在赘述运行截图,可以自己试试):

代码语言:txt
复制
public static void main(String[] args) {
		Singleton instance1 = Singleton.getInstance();
		Singleton instance2 = Singleton.getInstance();
		System.out.println(instance1 == instance2);
		System.out.println("instance1.hashCode=" + instance1.hashCode());
		System.out.println("instance2.hashCode=" + instance2.hashCode());
	}

懒汉式


所谓懒汉式,就是在需要调用的时候再创建类的实例化。

线程不安全

起到了懒加载效果,但是只能在单线程使用,多线程会不安全,因为当多个线程并发同时判断instance为空时,就会相应的实例化多个对象。

代码语言:txt
复制
class Singleton { //线程不安全
    private static Singleton instance;
    private Singleton() {}
    public static Singleton getInstance() {  //调用时才实例化对象,懒汉式
        if(instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

线程安全

上面线程不安全,那上锁不就好了,使用synchronized关键字。

这样虽然解决了线程安全,但其实实例化操作只做一次,而获取实例(即getInstance)的操作是很多次的,把调用的方法加上同步,会大大降低效率。

代码语言:txt
复制
class Singleton { //线程安全
    private static Singleton instance;
    private Singleton() {}
    //synchronized同步处理
    public static synchronized Singleton getInstance() {
        if(instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

双重检查


上面代码效率低,那判断一下有没有实例化不就好了,若没有实例化则用同步方法new一个,否则直接return即可。即所谓的双重检查。

需要用到关键字volatile,防止指令重排。如果不用volatile关键字,就会和线程不安全情形一样,在if判断那会有并发。

代码语言:txt
复制
class Singleton { //双重检查
	private static volatile Singleton instance;
	private Singleton() {}
	public static synchronized Singleton getInstance() {
		if(instance == null) { //判断是否实例化
			synchronized (Singleton.class) {
				if(instance == null) {
					instance = new Singleton();
				}
			}
		}
		return instance; //否则直接return
	}
}

这样既实现了懒加载,又保证了线程安全。

静态内部类


静态内部类在外部类装载时不会实例化,当调用的时候才会装载并实例化,且JVM保证了其装载时的线程安全性。也能保证懒加载和线程安全,有点像自带版的双重检查。

代码语言:txt
复制
class Singleton {
	private static volatile Singleton instance;
	private Singleton() {}
	//静态内部类,包含一个静态属性:Singleton
	private static class SingletonInstance {
		private static final Singleton INSTANCE = new Singleton(); 
	}
	//对外公有的静态方法,直接返回SingletonInstance.INSTANCE
	public static synchronized Singleton getInstance() {
		return SingletonInstance.INSTANCE;
	}
}

枚举


其实,使用枚举也能实现单例模式,不仅能避免多线程同步问题,也能防止反序列化重新创建新的对象。

代码语言:txt
复制
enum Singleton {
	INSTANCE; //属性
	public void say() {
		System.out.println("记得三连~");
	}
}

对应测试:

代码语言:txt
复制
public static void main(String[] args) {
		Singleton instance1 = Singleton.INSTANCE;
		Singleton instance2 = Singleton.INSTANCE;
		System.out.println(instance1 == instance2);
	
		System.out.println(instance1.hashCode());
		System.out.println(instance2.hashCode());
		
		instance.say();
	}

小结


单例模式使用的场景:

  1. 需要频繁的进行创建和销毁的对象
  2. 创建对象时耗时过多或耗费资源过多(重量级对象)
  3. 经常用到的对象、工具类对象、频繁访问数据库或文件的对象(数据源、session工厂)

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 饿汉式
    • 静态变量
      • 静态代码块
      • 懒汉式
        • 线程不安全
          • 线程安全
          • 双重检查
          • 静态内部类
          • 枚举
          • 小结
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档