如果要保证系统里一个类最多只能存在一个实例时,我们就需要单例模式。例如:缓存池,数据库连接池,线程池,一些应用服务实例等。
1、懒汉模式——实现懒加载但线程不安全
package singleton;
//懒汉模式(线程不安全)
public class Singleton1 {
private static Singleton1 instance;
private Singleton1() {
}
public static Singleton1 getInstance() {
if (instance == null) {
instance = new Singleton1();
}
return instance;
}
}
2、懒汉模式——实现懒加载,线程安全但效率低
public class Singleton2 {
private static Singleton2 instance;
private Singleton2() {
}
public static synchronized Singleton2 getInstance() {
if (instance == null) {
instance = new Singleton2();
}
return instance;
}
}
效率低。锁住整个方法,上述代码中的一次锁住了一个方法, 这个粒度有点大。只需锁住new 语句。
3、双重校验锁。实现懒加载,线程安全,且效率较第二种高(推荐掌握)
public class Singleton7 {
private volatile static Singleton7 singleton;
private Singleton7() {
}
public static Singleton7 getInstance() {
if (singleton == null) {
synchronized (Singleton7.class) {
if (singleton == null) {
singleton = new Singleton7();
}
}
}
return singleton;
}
}
4、饿汉模式——线程安全,但是无懒加载。
public class Singleton3 {
private static Singleton3 instance = new Singleton3();
private Singleton3() {
}
public static Singleton3 getInstance() {
return instance;
}
}
上述代码中的一个缺点是该类加载的时候就会直接new 一个静态对象出来,
当系统中这样的类较多时,会使得启动速度变慢 。现在流行的设计都是讲“延迟加载”,我们可以在第一次使用的时候才初始化第一个该类对象。所以这种适合在小系统。
5、饿汉模式(变种)——线程安全,但是无懒加载。
public class Singleton4 {
private static Singleton4 instance = null;
static {
instance = new Singleton4();
}
private Singleton4() {
}
public static Singleton4 getInstance() {
return instance;
}
}
本质上与第四中一样。
6、静态内部类——线程安全,实现懒加载。(推荐)
public class Singleton5 {
private static class SingletonHolder {
private static final Singleton5 INSTANCE = new Singleton5();
}
private Singleton5() {
}
public static final Singleton5 getInstance() {
return SingletonHolder.INSTANCE;
}
}
这种方式同样利用了classloder的机制来保证初始化instance时只有一个线程,它跟第三种和第四种方式不同的是(很细微的差别):第三种和第四种方式是只要Singleton类被装载了,那么instance就会被实例化(没有达到lazy loading效果),
而这种方式是Singleton类被装载了,instance不一定被初始化。因为SingletonHolder类没有被主动使用,只有显示通过调用getInstance方法时,才会显示装载SingletonHolder类,从而实例化instance。 想象一下,如果实例化instance很消耗资源,我想让他延迟加载,另外一方面,我不希望在Singleton类加载时就实例化,因为我不能确保Singleton类还可能在其他的地方被主动使用从而被加载,那么这个时候实例化instance显然是不合适的。这个时候,这种方式相比第三和第四种方式就显得很合理。
7、枚举——实现线程安全、懒加载、防止反序列化重新创建新的对象。本质上是最佳实现方式。
public enum Singleton6 {
INSTANCE;
public void whateverMethod() {
}
}
讨论:
单例模式与垃圾回收
当一个单例的对象长久不用时,不会被jvm的垃圾收集机制回收。
http://blog.youkuaiyun.com/zhengzhb/article/details/7331354
参考博客:
http://cantellow.iteye.com/blog/838473
http://blog.youkuaiyun.com/zhengzhb/article/details/7331369