单例模式总结
描述
Singleton Pattern:
Ensure a class has only one instance, and provide a global point of access to it.(确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。)
实现
懒汉式
// 经典实现方式
public class Singleton{
// 唯一实例,私有并且静态
private static Singleton uniqueInstance;
// 私有化构造器
private Singleton(){}
// 静态方法 获取单例
public static Singleton getInstance(){
// 懒汉式,如果我们不需要这个实例,它就永远不会产生
if (uniqueInstance == null){
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
缺点:线程不安全
如果两个线程同时调用 getInstance() 方法,同时进入if语句,那么就会创造两个实例
懒汉式—加锁
public class Singleton{
private static Singleton uniqueInstance;
private Singleton(){}
//通过增加 synchronized 关键字到 getInstance 方法,使得不会有两个线程同时进入这个方法。
public static Synchronized Singleton getInstance(){
if (uniqueInstance == null){
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
缺点:性能差
每次调用 getInstance() 都会加锁
懒汉式— DCL 双重锁
public class Singleton{
// volatile 关键字确保 当uniqueInstance 变量被初始化成 Singleon实例时
// 多个线程正确地处理uniqueInstance变量
private volatile static Singleton uniqueInstance;
private Singleton(){}
public static Singleton getInstance(){
// 检查实例,如果不存在,则进入同步区块,如果存在,直接返回
if(uniqueInstance == null){// 只有第一次才会彻底执行这里的代码块
Synchronized(Singleton.class){
if(uniqueInstance == null){//进入区块后,再检查一次,如果仍是null,才创建实例
uniqueInstance = new Singleton;
}
}
}
return uniqueInstance;
}
}
优点:大大减少getInstance() 方法的时间耗费
饿汉式
天然线程安全
public class Singleton{
private static Singleton uniqueInstance = new Singleton();
private Singleton(){}
public static getInstance(){
return uniqueInstance;
}
}
扩展
写一个多例模式
public class MultiPattern{
// 必须要有容器
private static List<Chess> chessList = new ArrayList<>();
private static final Chess whiteChess = new Chess("white");
private static final Chess blackChess = new Chess("black");
private static final int maxCount = 2;
static{
chessList.add(whiteChess);
chessList.add(blackChess);
}
// 私有化构造器
private MultiPattern(){}
public static Chess getInstance(){
Random random = new Random();
int crt = random.nextInt(maxount);
return chessList.get(crt);
}
public static Chess getInstance(int index){
return chessList.get(index);
}
}