记得刚开始涉足程序的时候, 去笔试 ,发现有一个笔试题经常粗线,写一个单例模式的基本实现, 当时没研究设计模式也就不知为何物,
到今日 , 才发现它已成为我日常开发最常用的一种设计模式。
我写的所有设计模式的代码都会用java 呈现, 虽然第一个学习的是c++但是 最开始作为工作的是java,并且有点偏好java
单例模式 , 意思就是 整个系统仅只有此类的一个实力, 当然这只是狭义的单例,经常看到变种的单例是允许,创建指定数量的实例的
单例模式是一种创建型模式。 它是优化的一种策划, 避免重复创建销毁一个对象(创建销毁对象是有开销的), 有点像对象池的概念。
我写博文 纯粹是对自己所了解的东西的一个回顾, 不保证权威性。 仅希望 迷途的新手能在我的博文中
有所收获,我也尽量 用我最简单的语言 去描述 我对 很多东西的理解、(这段话会在我的每一个博文里面出现 因为 我不是一个看了书 做笔记的博客,
而是我进行思考的博客 ,当然也希望大牛可以批评指正)
下面给出一个最简单的单例的实现
1 public class HelloSingleton {
2
3 private static HelloSingleton w_Instance = new HelloSingleton();
4
5 //定义一个私有的构造函数,确保在该类的外部无法生成类的实例
6 private HelloSingleton(){
7
8 }
9
10 public static HelloSingleton getInst(){
11 return w_Instance;
12 }
13 }
这一种单例模式被成为饿汉模式, 其实意思就是开始的时候就实例好了 对象, 缺点是没有做到延迟加载
(延迟加载是一种优化策略,在需要的时候再去加载)这个用起来比较简便
然后下面是 另外一种单例模式,懒汉模式
public class HelloSingleton {private static HelloSingleton w_Instance;
//定义一个私有的构造函数,确保在该类的外部无法生成类的实例
private HelloSingleton(){}
public static HelloSingleton getInst(){
if(w_Instance == null){
w_Instance = new HelloSingleton();
}
return w_Instance;
}
}
public class HelloSingleton {private static HelloSingleton w_Instance;
//定义一个私有的构造函数,确保在该类的外部无法生成类的实例
private HelloSingleton(){}
public static HelloSingleton getInst(){
if(w_Instance == null){
w_Instance = new HelloSingleton();
}
return w_Instance;
}
}
网上看到,或者大多数人都是如此写懒汉模式的, 这种写法在单线程环境下是安全的, 但是在多线程环境下 会造成生成多个实例的问题
比如现成A正在访问 getInst()方法 ,线程A读到w_Instance 为null
,创建该类对象并返回,线程B正好在此时也访问getInst方法,此时现成A构造的实例现成B无法看见,因为多线程环境中非同步代码快无法保证共享变量的可见性。所以该写法是有问题的,
调整为如下则不会在多线程环境下出现创建多个实例的问题。
1 public class HelloSingleton {
2
3 private static HelloSingleton w_Instance;
4
5 //定义一个私有的构造函数,确保在该类的外部无法生成类的实例
6 private HelloSingleton(){
7
8 }
9
10 public static synchronized HelloSingleton getInst(){
11 if(w_Instance == null){
12 w_Instance = new HelloSingleton();
13 }
14 return w_Instance;
15 }
16 }
1 public class HelloSingleton {
2
3 private static HelloSingleton w_Instance;
4
5 //定义一个私有的构造函数,确保在该类的外部无法生成类的实例
6 private HelloSingleton(){
7
8 }
9
10 public static synchronized HelloSingleton getInst(){
11 if(w_Instance == null){
12 w_Instance = new HelloSingleton();
13 }
14 return w_Instance;
15 }
16 }
java用synchronized保证同步代码快。 同步代码快 既保证 变量的原子性,也保证变量的可见性。
上面是最简单的两种单例的写法,但是为了扩展 , 还是介绍一些 其他的 常见的单例的写法。
effective java作者 推崇的 用枚举的方式实现的 singleton
1 public enum HelloSingleton {
2
3 Instance;
4
5 }
额 你没有看错 就是这个样子的 , 起初 看到这个代码 , 我也很疑惑 , 这个是单例吗, 但是确实它也实现了单例 模式。
java的枚举不同于 c++ , c#等语言, java的枚举是用对象实现的, 所以此枚举里 仅有一个对象
它的优点是这么介绍的 优点:不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象
第四种单例,采用静态内部类型, 我的同时 很多次 跟我讲 他觉得java的内部类真的是很扯淡的设计, 不知道是干什么用的,
但是我个人感觉java的内部类让java 语言用起来更灵活, 比如我 不想让别人使用的类 仅仅想在一个对象里面使用的类 ,就可以用private 定义一个
内部类 , 别人无须知道 内部实现。 更好的实现封装的思想,
代码示意图如下
1 public class HelloSingleton {
2 private static class SingletonHolder
3 {
4 private final static HelloSingleton w_Instance = new HelloSingleton();
5 }
6
7 private HelloSingleton(){
8
9 }
10
11 public static HelloSingleton getInst(){
12 return SingletonHolder.w_Instance;
13 }
14 }
此类型看起来比较晦涩 好像绕了不烧 ,
这样写的好处是:加载时不会初始化静态变量INSTANCE,因为没有主动使用,达到延迟加载
还有一个类型就不介绍了 ,因为个人 基本没用到过, 感觉自己最常用的就是第二种, 懒汉式 , 单例。
设计模式, 单例, 就是这么简单 。
关于单例的变种你可以这么想 , 有的时候 你会想让单例 生成指定数量的 实例, 具体实现就是在 类里面加个 数量, 然后每次getInst
的时候去判断 是否达到最大数量, 如果达到就不在生成新的实例 ,如果没有,就生成新的实例返回, 好了 单例 就这么简单, 感觉没什么好说的 就写到这里