本篇文章主要介绍了"设计模式-单例模式(Singleton Pattern)",主要涉及到singleton,pattern方面的内容,对于软件工程感兴趣的同学可以参考一下:
本文由@呆代待殆原创,转载请注明出处。 单例模式简述单例模式保证了我们的类只有一个实例,并且我们在任何时候都可以取得这个实例,其中保证我们的类有且仅有一个实例在...
举例:想象一下情况,线程A执行到代码的第5行,判断成功,在准备进入第6行的时候CPU切换了,线程B恰好也执行这段代码,这时很明显instance还是==null的浴室线程B成功创建了一个instance的实例,结果,当CPU又切回线程A时,麻烦来了,线程A继续执行第6行代码又创建了一个instance的实例,并把原来的那个覆盖了,这就很有可能导致意想不到的问题。
所以,我们必须想办法解决这个问题,这里我们提供以下几种思路。
饿汉式:不再等到要使用的时候才创建,而是在程序开始的时候就创建好(对这个实例很饥渴的样子,所以叫饿(chi)汉式)
1publicclass MySingleten {
2publicstatic MySingleten instance=new MySingleten();//一开始就生成这个变量就不存在线程问题了 3private MySingleten(){}
4public static MySingleten getInstance(){
5return instance;
6 }
7publicvoid MyFunction(){
8 System.out.println("我是单例,这是我的方法");
9 }
10 }
synchronized方法:直接在懒汉式的getInstance方法前加上synchronized修饰符,这样就能解决线程安全问题了,这个解决方法是最简单的,但是效率却非常低下,因为只有第一次创建实例的时候这个synchronized是有必要的,当实例创建完成后,这个synchronized就只剩下拖慢速度的作用了。
1publicclass MySingleten {
2publicstatic MySingleten instance=null;
3private MySingleten(){}
4public staticsynchronized MySingleten getInstance(){
5if(null==instance){
6 instance=new MySingleten();
7 }
8return instance;
9 }
10publicvoid MyFunction(){
11 System.out.println("我是单例,这是我的方法");
12 }
13 }
双重加锁方法:在懒汉式的基础上,我们可以用两把锁来分别控制单例的取得和创建,因为只需要在第一次创建单例的时候注意线程安全问题,那么,我们在内层锁上用synchronized来控制,在外层锁上用 if(null==instance) 来判断是否存在这个实例,这样就省去了synchronized在后来浪费的同步时间
1publicclass MySingleten {
2publicvolatilestatic MySingleten instance=null;//注意这里增加了volatile关键字 3private MySingleten() {}
4public static MySingleten getInstance() {
5if (null == instance) {// 外层锁,判断是否实例已经被创建 6synchronized (MySingleten.class) {// 内层锁控制线程间同步,实例被创建后就没有运行的机会了,省去了多余的线程间同步成本 7if(null==instance)//需要再次检查,因为很有可能线程A在这里时,线程B已经通过外层的if了。 8 instance = new MySingleten();
9 }
10 }
11return instance;
12 }
13publicvoid MyFunction() {
14 System.out.println("我是单例,这是我的方法");
15 }
16 }
静态全局变量和单例模式的对比
1,静态全局变量并不能保证对象是唯一的(既然你能创建这个静态全局变量就说明这个类的构造函数并不是私有的)。
2,多余的全局变量会造成命名空间的污染。
3,全局变量总是存在,会一直占用内存,而单例模式可实现访问的时候再创建单例的实例。
4,单例模式产生的对象保存在堆里,但是静态全局变量保存在栈里。
静态成员和单例模式的对比