讲完了设计原则,开始进行对设计模式的理解与应用;每个模式,我们都从场景、定义、编码、问题反思等几个方面来分享;
单例模式-场景:
1.一个党只能有一个主席。
2.Windows的文件只能被一个实例访问。
3.一次性只能连接一台打印机执行打印。
对于系统的研发来说,每多一个实例,会多占用一定内存,而内存是相对有限的。
定义:确保一个类仅有一个唯一的实例,并且提供一个全局的访问点;
编码:
public class Singleton {
//唯一的对象保存在单例类的属性里
private static Singleton instance = null;
// 构造器私有化,不能在类的外部随意创建对像
private Singleton() {
}
//获取唯一实例
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
这样在单线程上是OK的,一单出现多线程,就会有多个实例被创建,如此违反了我们的初衷;
为何不安全,先进行代码测试:
public class Singleton {
// 为了记录这个 Singleton 类被实例化的次数
// 声明static 类型的计数器
private static int count;
//唯一的对象保存在单例类的属性里
private static Singleton instance = null;
// 构造器私有化,不能在类的外部随意创建对象
private Singleton() {
System.out.println("Singleton 私有的构造方法被实例化 " + (++count) + " 次");
}
public static Singleton getInstance() {
//在判断null的时候,另外线程会先进行实例化,而此时当前的线程判断依然为null;
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
测试Demo:
public class SingletonPatternDemo {
public static void main(String[] args) {
Runnable task = ()->{
String threadName = Thread.currentThread().getName();
Singleton s1 = Singleton.getInstance();
System.out.println("线程 " + threadName + "\t => " + s1.hashCode());
};
// 模拟多线程环境下使用 Singleton 类获得对像
for(int i=0;i<10;i++){
new Thread(task,"" + i).start();
}
}
}
结果:
Singleton 私有的构造方法被实例化 1 次
Singleton 私有的构造方法被实例化 4 次
线程 1 => 1316319194
Singleton 私有的构造方法被实例化 3 次
Singleton 私有的构造方法被实例化 2 次
线程 0 => 2140408704
线程 9 => 2140408704
线程 2 => 840831472
线程 4 => 2140408704
线程 5 => 325223395
线程 8 => 2140408704
线程 3 => 1316319194
线程 7 => 2140408704
线程 6 => 2140408704
如何解决呢? 部分同学采用如下这种方式,但是如此一来会在服务器加载该类时就创建了实例,而不是需要的时候就创建实例,设计不够优雅。
public class Singleton {
// 为了记录这个 Singleton 类被实例化的次数
// 声明static 类型的计数器
private static int count;
//唯一的对象保存在单例类的属性里
private static Singleton instance = new Singleton();
// 构造器私有化,不能在类的外部随意创建对
private Singleton() {
System.out.println("Singleton 私有的构造方法被实例化 " + (++count) + " 次");
}
public static Singleton getInstance() {
return instance;
}
}
有没有更好的方式呢?可以看看如下:
public class SingletonDemo {
private static int count;
private static class SingletonHolder{
private static SingletonDemo instance = new SingletonDemo();
}
private SingletonDemo(){
System.out.println("SingletonDemo 私有的构造方法被实例 " + (++count) + " 次");
}
public static SingletonDemo getInstance(){
return SingletonHolder.instance;
}
}