单例模式主要用来产生一个对象的具体实例,它可以确保系统中一个类只产生一个实例。
两个好处:
- 对于频繁使用的对象,可以省略new操作花费的时间
- new的次数少了,对系统内存的使用频率就小了,那么GC压力就会降低,缩短了GC停顿时间
饿汉式单例模式:
public class Singleton { private Singleton() { System.out.println("Singleton iscreate"); } private static Singleton instance = new Singleton(); private static Singleton getInstance() { return instance; } }
私有化构造方法的作用:不能new这个类的实例,从而避免该类被错误的创建
因此要想获取这个对象,只能调用getInstance()工厂方法,构造方法被私有化,要想这个方法可以被调用,所以这个方法必须用static修饰,调用方式:类.方法名
从而instance也必须用static修饰。
好处:性能非常好,getInstance()方法只是简单的返回instance,并没有任何锁操作,所以在并行程序中它会有很好的表现
坏处:Singleton构造函数或者说Singleton实例在什么时候创建是不受控制的,对于静态成员instance,它会在类第一次初始化的时候被创建,并不是第一次调用getInstance()方法的时候被创建的
延伸一点:static修饰的成员变量所属类被加载的时候,变量间会被分配空间,及就会被创建
懒汉式单例模式:
public class LazySingleton { private LazySingleton() { System.out.println("LazySingleton is create"); } private static LazySingleton instance = null; private static synchronized LazySingleton getInstance() { if (instance == null) instance = new LazySingleton(); return instance; } }
私有化构造方法的作用:不能new这个类的实例,从而避免该类被错误的创建
只有当调用getInstance()方法时才会创建单例对象,为了防止对象被多次创建,还须要使用synchronized进行方法同步
好处:充分利用了延迟加载,只有在真正需要时才会创建对象
坏处:并发环境下加锁,竞争激烈的场合对性能会产生一定影响
另外还有一种,双重判断加双同步(安全又高效):
public class SingleTon { private static volatile SingleTon singleTon = null; private SingleTon() { } public static SingleTon getInstance() { if (singleTon == null) { synchronized (SingleTon.class) { if (singleTon == null) { singleTon = new SingleTon(); } } } return singleTon; } }
为什么双重判断:
如果单层if判断,在服务器允许的情况下,假设有一百个线程,耗费的时间为100*(同步判断时间+if判断时间),而如果双重if判断,100的线程可以同时if判断,理论消耗的时间只有一个if判断的时间。
所以如果面对高并发的情况,而且采用的是懒汉模式,最好的选择就是双重判断加同步的方式。