Singleton设计模式,确保全局只存在一个该类的实例。将构造器声明为private,防止调用(虽然仍是可使用反射来调用)。声明一个静态的类实例在类中,声明一个公共的获取实例的方法。这篇博文给出了简单的实现方法,分析如何作到线程安全,整理了使用Singleton的坏处。java
方法一是线程安全的,在类被装载的时候,就初始化这个成员,Java库中Runtime就是用了这个方法。
方法二不是线程安全的。若是多个线程同时进入到函数中(临界区),那么会返回多个不一样的实例。设计模式
代码验证安全
如下代码验证了线程不安全,即多线程的状况下方法二不能保证真正的“单例”。经过打印每一个类的hashCode来显示,类实例不惟一。多线程
class Singleton { private static Singleton singleton; private Singleton() {} public static Singleton getInstance() { if (singleton == null) { try { Thread.sleep(233); singleton = new Singleton(); } catch (Exception e) { e.printStackTrace(); } } return singleton; } } public class Main { public static void main(String args[]) { for (int i = 0; i < 10; i++) { new Thread(new Runnable() { public void run() { Singleton singleton = Singleton.getInstance(); System.out.println(singleton.hashCode()); } }).start(); } } }
解决方案ide
一种简单的处理方法是,将getInstance声明为synchronized的,效率低,由于每个线程都在等待进入临界区。函数
另外一种方法叫作Double Checked Locking(DCL),将公共变量声明为volatile(每次要使用这个变量的时候,从内存中取出来,保证各个线程能够看到这个变量的修改)。单元测试
class Singleton { private volatile static Singleton singleton; private Singleton() {} public static Singleton getInstance() { if (singleton == null) { try { Thread.sleep(233); synchronized (Singleton.class) { if (singleton == null) { singleton = new Singleton(); } } } catch (Exception e) { e.printStackTrace(); } } return singleton; } }
有啥坏处,别怪这个设计模式,都是全局变量的错。测试
1, 全局变量线程
Singleton管理公共的资源,在代码中的任何地方,只要调用Singleton的获取实例的方法,就能够获取到Singleton的实例,能够对这些公共资源的读写。这让Singleton成为了一个全局变量。设计
全局变量的坏处,也是Singleton的坏处。全局变量自有全局变量的使用情景和优势,要分开两面看待,这里只讲坏处并不是想说全局变量一无可取。
在分析全局变量的坏处以前,在[2]下面看到了一个特别有意思的比喻:
Using global state with your fellow programmers is like using the same toothbrush with your friends - you can but you never know when someone will decide to shove it up his bum.
我想这位老兄说出这个观点,大概是用过异味的牙刷吧。为什么不用规范来约束一同使用全局变量的人呢?
这位老兄道出了全局变量的本质,任何人能够用它作任何事,给整个程序带来了极大的不肯定性。网上关于全局变量的坏处讨论不少,下面整理了一些,虽然并不是都很坏:
2, 破坏了单一职责原则
定义:就一个类而言,应该仅有一个引发它变化的缘由
当一个类使用了Singleton的时候,它不只负责这个类须要完成的任务,还负责这个单一对象资源的建立和管理。这个类的函数作两项任务,相关性低。
这一点算不上太坏。毕竟设计原则并不老是须要遵照的。
上面讲了坏处,核心要义是避免将Singleton用做全局变量。Singleton的使用场景是什么呢?
回到Singleton的本质做用上来,只须要一个这个类的实例。前面讲这个设计模式破坏了单一职责原则,由于须要管理这个实例。
因此归结起来使用这个设计模式的两个缘由:
(1) 单个实例
(2) 实例的管理
在[1]中讲了使用Singleton的一个具体例子。那就是日志(log)。由于log和代码的实质功能并不会产生耦合,因此是否开启log对于系统的功能没有太大的影响。