记得刚开始涉足程序的时候, 去笔试 ,发现有一个笔试题常常粗线,写一个单例模式的基本实现, 当时没研究设计模式也就不知为什么物,java
到今日 , 才发现它已成为我平常开发最经常使用的一种设计模式。c++
我写的全部设计模式的代码都会用java 呈现, 虽然第一个学习的是c++可是 最开始做为工做的是java,而且有点偏好javac#
单例模式 , 意思就是 整个系统仅只有此类的一个实力, 固然这只是狭义的单例,常常看到变种的单例是容许,建立指定数量的实例的设计模式
单例模式是一种建立型模式。 它是优化的一种策划, 避免重复建立销毁一个对象(建立销毁对象是有开销的), 有点像对象池的概念。安全
我写博文 纯粹是对本身所了解的东西的一个回顾, 不保证权威性。 仅但愿 迷途的新手能在个人博文中 有所收获,我也尽可能 用我最简单的语言 去描述 我对 不少东西的理解、(这段话会在个人每个博文里面出现 由于 我不是一个看了书 作笔记的博客, 而是我进行思考的博客 ,固然也但愿大牛能够批评指正)多线程
下面给出一个最简单的单例的实现函数
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; } }
网上看到,或者大多数人都是如此写懒汉模式的, 这种写法在单线程环境下是安全的, 可是在多线程环境下 会形成生成多个实例的问题spa
好比现成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 的时候去判断 是否达到最大数量, 若是达到就不在生成新的实例 ,若是没有,就生成新的实例返回, 好了 单例 就这么简单, 感受没什么好说的 就写到这里