- 特征
- 引入
- 多线程
- 如何改善多线程?
- 方法一、“急切”创建实例
- 方法二、“双重检查加锁”,在getInstance()中减少使用同步
- 面试常用
- 单例模式虽然只有一个类,但是可能会导致多线程难以同步之类的问题,它适合什么场景呢?
- 难道不能创建一个类,把所有的方法和变量都定义为静态的,把类直接当成一个单件?
- 那么类加载器呢?听说两个类可能有机会各自创建自己的单例实例。
- 想把单件类设计成超类,设计出子类,究竟可以不可以继承单件类?
- 为什么全局变量比单例模式差?
- 要点
类图上只有一个类
引入很多情况下,只有一个对象,比如线程池(threadpool)、缓存(cache)、处理偏好设置和注册表(registry)的对象。这类对象只有一个实例,多个实例反而会造成很多问题。
- 单例对象的构造器是私有的。
- 有一个静态方法getInstance(),调用它来开启工作
- if(uniqueInstance == null)表示如果我们不需要这个实例,他就永远不会产生,这就“延迟实例化”(lazy instantiaze)
public class SingLeton{
//利用一个静态变量来记录SingLeton类的唯一实例
private static SingLeton uniqueInstance;
private SingLeton(){}
public static SingLeton getInstance(){
if(uniqueInstance == null){
uniqueInstance = new SingLeton();
}
return uniqueInstance;
}
//其他方法
}
多线程
多线程可能会造成一定的问题
如何处理多线程呢?
public static synchronized SingLeton getInstance()
public class SingLeton{
//利用一个静态变量来记录SingLeton类的唯一实例
private static SingLeton uniqueInstance;
private SingLeton(){}
public static synchronized SingLeton getInstance(){
if(uniqueInstance == null){
uniqueInstance = new SingLeton();
}
return uniqueInstance;
}
//其他方法
}
通过新增synchronized关键字到getInstance()方法中,迫使每个线程进入方法前,要先等别的线程离开该方法,即同一时间不会有多个线程进入该方法。uniqueInstance在设置好后,就不需要同步了。频繁引用getInstance()程序外加使用同步会导致程序执行效率下降100倍。
如何改善多线程? 方法一、“急切”创建实例如果程序总是使用单例或者创建和运行时程序负担较小,可以“急切”创建实例,而不是用延迟实例化的做法。JVM保证任何线程访问uniqueInstance静态变量前,一定先创建此实例。
public class SingLeton{
//利用一个静态变量来记录SingLeton类的唯一实例
private static SingLeton new SingLeton();
private SingLeton(){}
public static SingLeton getInstance(){
return uniqueInstance;
}
//其他方法
}
方法二、“双重检查加锁”,在getInstance()中减少使用同步
首先检查是否创建了实例,如果尚未创建,“才”进行同步。
public class SingLeton {
//利用一个静态变量来记录SingLeton类的唯一实例
private volatile static SingLeton uniqueInstance;
private SingLeton() {
}
public static SingLeton getInstance() {
if (uniqueInstance == null) {
synchronized (SingLeton.class) {
if (uniqueInstance == null) {
uniqueInstance = new SingLeton();
}
}
}
return uniqueInstance;
}
}
volatile
某个属性被多个线程共享,其中有一个线程修改了此属性,其他线程可以立即得到修改后的值
两次检查uniqueInstance为null,先进入同步再确定null才进行实例化。
A1:正确使用单例模式的方法有三种,使用同步机制,“急切”创建单例,或者双检测+同步机制。当需要控制实例个数的时候还是应当先用单例模式。
难道不能创建一个类,把所有的方法和变量都定义为静态的,把类直接当成一个单件?A2: 当这样做时,由于构造方法是静态的,容易产生和初始化有关的bug,尤其是多个类时,更容易产生问题,所以建议使用对象的单例。
那么类加载器呢?听说两个类可能有机会各自创建自己的单例实例。A3: 不同的类加载器会导致同一个类被加载多次,多个单件并存的情况。所以如果程序中有多个类加载器,又同时使用了单件模式,需要自行指定同一个类加载器。
想把单件类设计成超类,设计出子类,究竟可以不可以继承单件类?A4: 继承单件类遇到的问题就是构造器是私有的。如果修改构造器的访问权限,单件的实现是利用静态变量,直接继承会导致所有的派生类共享同一个实例变量。
为什么全局变量比单例模式差?单例模式的作用是确保只有一个实例并提供全局访问。全局变量实际上就是对对象的静态引用,这样的情况下就不能是根据我们需要来创建对象,“延迟实例化”和“急切”创建就是个例子,其中“急切”创建实例不能考虑到我们的需要。
要点实现单件模式需要私有的构造器,一个静态方法和一个静态变量。
如果使用多个类加载器,可能会导致单件失效而产生多个实例。
结束啦~
我讲清楚了吗?觉得不错的话点个~



