题目
设计一个类,只能生成这个类的一个实例
单例模式是 GOF
23 种设计模式当中的一种,实现起来较为简单,只需要将构造方法设置为私有 priavte
,并提供一个静态方法获取该类实例即可。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class Singleton{ private static Singleton singleton = null; private Singleton(){ } public static Singleton getInstance(){ if (singleton == null) { singleton = new Singleton(); } return singleton; } }
|
想要获取 Singleton
这个类的实例的话只需如下代码即可
1
| Singleton singleton = Singleton.getInstance();
|
但是这种写法有一个问题,多线程情况下调用 getInstance()
方法时可能会被其他线程抢占执行权,最终生成多个实例。
因此,在多线程情况下,为保证单实例,需要加锁。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class Singleton{ private static Singleton singleton = null; private Singleton(){ } public static Singleton getInstance(){ synchronized(Singleton.class){ if (singleton == null) { singleton = new Singleton(); } } return singleton; } }
|
这样写已经没什么大问题了,每一个线程获取 Singleton
实例的时候都需要去拿锁,拿到锁之后生成实例,最终生成的实例只有一个。
但是如果考虑到性能的因素,那么还有更好的写法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public class Singleton{ private static Singleton singleton = null; private Singleton(){ } public static Singleton getInstance(){ if (singleton == null) { synchronized(Singleton.class){ if (singleton == null) { singleton = new Singleton(); } } } return singleton; } }
|
加锁会影响方法调用的效率,如果在拿锁之前进行判定是否实例化的话可以节省很多时间,这种写法能在保证多线程安全的前提下保持性能。
当然上面这种双锁的方式较为复杂,如果不在乎内存的话,可以采用饿汉式,类加载就初始化实例,这样的话也能保证线程安全和高性能。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class Singleton{ private static Singleton singleton = new Singleton(); private Singleton(){ } public static Singleton getInstance(){ return singleton; } }
|
Effctive Java
的作者则提倡使用enum
来实现单例模式,保证线程安全并且还支持序列化,不过Java
在1.5
之后才加入enum
机制,在兼容性上可能有些问题。
我还没来得及拜读Effctive Java
,因此这种写法不是很了解,有兴趣可以自己去看看。
最后更新时间: