编译时初始化
- // 在自己内部定义自己一个实例,是不是很奇怪?
- // 注意这是private 只供内部调用
- private static Singleton instance = new Singleton();
- // 这里提供了一个供外部访问本class的静态方法,可以直接访问
- public static Singleton getInstance() {
- return instance;
- }
使用时实例化
- private static Singleton instance = null;
- public static synchronized Singleton getInstance() {
- // 这个方法比上面有所改进,不用每次都进行生成对象,只是第一次
- // 使用时生成实例,提高了效率!
- if (instance == null)
- instance = new Singleton();
- return instance;
- }
- 注意到lazy initialization形式中的synchronized,这个synchronized很重要,如果没有synchronized,那么使用getInstance()是有可能得到多个Singleton实例。
使用场景
EventBus中也采用了单例,因为它内部缓存了各个组件发送过来的event对象,并负责分发出去,各个组件需要向同一个EventBus对象注册自己,才能接收到event事件,肯定是需要全局唯一的对象,所以采用了单例。
EventBus的单例采用的是双重检查加锁单例
static volatile EventBus defaultInstance;
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
单例不需要维护任何状态,仅仅提供全局访问的方法,这种情况考虑使用静态类,静态方法比单例更快,因为静态的绑定是在编译期就进行。
如果你需要将一些工具方法集中在一起时,你可以选择使用静态方法,但是别的东西,要求单例访问资源并关注对象状态时,应该使用单例模式。
如果你需要将一些工具方法集中在一起时,你可以选择使用静态方法,但是别的东西,要求单例访问资源并关注对象状态时,应该使用单例模式。
适用场合
- 需要频繁的进行创建和销毁的对象;
- 创建对象时耗时过多或耗费资源过多,但又经常用到的对象;
- 工具类对象;
- 频繁访问数据库或文件的对象。
优点
系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能。
由于单例模式在内存中只有一个实例,减少了内存开销。
单例模式可以避免对资源的多重占用,例如一个写文件时,由于只有一个实例存在内存中,避免对同一个资源文件的同时写操作。
单例模式可以再系统设置全局的访问点,优化和共享资源访问。
其中使用到单例模式时,考虑较多的就是多线程的情况下如何防止被多线程同时创建等问题,其中《Head First Design Patterns》使用到“double-checked locking”来降低使用synchronization。
当这个类的对象在多个地方创建的时候,使得内部的方法多次调用,但是希望只要一个对象操作这个方法,或者不希望多个地方同时调用这个方法,需要保持这个方法的单一性质,就用单利模式
缺点
当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用new,可能会给其他开发人员造成困扰,特别是看不到源码的时候。