在做项目时遇到了一个高并发获得token问题,这里设计的时候借鉴了单例模式中double check的思想,所以在此记录单例模式。本文会给出如何实现一个单例模式例子,在面试中可能遇到。
单例模式
单例,单个例子,也就是单个对象。一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
实现单例类注意以下三点:
1、单例类只有一个实例对象
2、该实例对象由单例类自己创建
3、单例类向外提供获取实例的方法
单例模式优缺点
优点:
1、内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例。
2、避免对资源的多重占用。
缺点:
1、没有接口,不能继承,进行扩展十分困难。
2、单例类职责过重,与单一职责原则冲突,
3、如果将数据库连接池对象设计为的单例类,可以节省资源,但是当共享该连接池对象过多时,连接池会溢出。
单例模式实现
首先我们要了解单例模式中两个模式,饿汉式与懒汉式。
饿汉式:
饿汉式在连单例类在加载的时候就将自己实例化,没有实现延迟加载,从资源利用的角度不如饿汉,而且因为加载时就实例,所以加载时间会比较长。但无需考虑多线程的问题。
饿汉式实现方法:
public class Singleton{
//在静态初始化器中创建单例,保证了线程安全性
private static Singleton singleton= new Singleton();
private Singleton() {}
public static Singleton getInstance(){
return singleton;
}
}
懒汉式:
懒汉式在单例类第一次使用的时候进行创建,实现了延迟加载,此处为了处理多个线程同时访问的问题,采用了double check的机制控制。
懒汉式实现方法:
public class Singleton{
//使用volatile关键字,确保当singleton变量被初始化成为Singleton实例时,多线程可以正确地处理singleton变量。
private volatile static Singleton singleton;
private Singleton() {}
public static Singleton getInstance() {
if(singleton == null){//第一次检查
synchronized(Singleton.class){
if(singleton== null){//第二次检查
singleton = new Singleton();
}
}
}
return singleton;
}
}
一种更好的单例模式实现
饿汉式不能实现延迟加载,始终占据内存;懒汉式需要控制线程,而且性能受影响。而接下来这种方法可以克服两个类的缺点。
在类中增加一个静态(static)内部类,在该内部类中创建单例对象,再将该单例对象通过getInstance()方法返回给外部使用,实现代码如下所示:
public class Singleton
{
private Singleton()
{
}
private static class HolderClass
{
private final static Singleton instance = new Singleton();
}
public static Singleton getInstance()
{
return HolderClass.instance;
}
}