Singleton的三种形式+怎么实现真正的单例

以前用singleton的时候就接触过饿汉懒汉两种

最近书上看到一个对于我来说是新的方法,感觉还是很不错的

这里将三种方法放一起,比较总结一下


一、饿汉式

package com.aii.algorithm;

public class HungrySingleton {

	private HungrySingleton() {
	}

	private static HungrySingleton instance = new HungrySingleton();

	public static HungrySingleton getInstance() {
		return instance;
	}
}

缺点:

该类有一个静态的常量instance,这个instance实例在这个类加载到内存的时候就已经初始化。

类什么时候被加载进内存:当然是第一次使用到的时候,如果这个类里还有其他静态方法,如

public static void print(){
System.out.println("1111");
}

那么当调用HungrySingleton.print()的时候,就自动生成了一个instance对象,如果这个对象又很大,那么留在内存中影响性能。

使用懒加载的方式可以避免过早实例化。


二、懒汉式

<pre name="code" class="java" style="font-size: 13.3333339691162px;">package com.aii.algorithm;

public class LazySingleton {

	private LazySingleton() {
	};

	private static LazySingleton instance = null;

	public static LazySingleton getInstance() {
		if (instance == null) {
			synchronized (LazySingleton.class) {
				if (instance == null) {
					instance = new LazySingleton();
				}
			}
		}
		return instance;
	}
}

 


懒汉式有一个优点,那就是懒加载。

懒加载有什么好处:

当前类如果实例化对象会非常大,调用他的静态方法的时候,根本没有必要初始化instance,这个时候使用饿汉式会多出这个大对象,而懒汉式不会。

缺点:

具体什么时候实例化,得看调用而定,所以在初始化的时候得做判断。

但是多线程的环境下,又能产生多个对象,所以得加锁。

但是每次判断前都加锁,每次调用都先进锁,难免影响性能。

所以使用双重判断。

所以缺点就是程序写起来麻烦。。。。



三、内部类

<pre name="code" class="java">package com.aii.algorithm;

public class InnerSingleton {

	private static class Inner {
		private static InnerSingleton instance = new InnerSingleton();

		static InnerSingleton get() {
			return instance;
		}
	}

	public static InnerSingleton getInstance() {
		return Inner.get();
	}

	private InnerSingleton() {
	}
}

 

这个方法非常巧妙:

把类的实例放到内部类中:

什么时候实例化呢?只有当内部类被加载到内存的时候。

内部类什么时候被加载到内存?只要我这个类不调用你,永远也不会进内存(外面的类访问不到)


四、真正的单例

学习了反射后,发现上面的单例都是可破解的,很容易能够弄到第二个对象。

那么怎么样才能真正做到单例呢?

Unsafe这个类给了我一些启发,因为在我用反射直接去直接获取他的对象的时候会报错。

然后可以考虑一下下面的方法。

package com.aii.algorithm;

public class HungrySingleton {
	private static boolean flag = false;

	private HungrySingleton() {
		if (flag) {
			throw new RuntimeException();
		}
	}

	private static HungrySingleton instance = newInstance();

	public static HungrySingleton getInstance() {
		return instance;
	}

	private static HungrySingleton newInstance() {
		HungrySingleton instance = new HungrySingleton();
		flag = true;
		return instance;
	}
}

写到这里发现,好像还是可以通过反射改变flag的值的,,,不过就当是加了一层保障把。。。


五、用法


平常用的话,如果一定要单例,简单起见,用饿汉式即可。

如果这个对象非常大,并且经常调用他的静态方法而不使用他的对象,那么可以考虑使用懒汉式或者内部类,毕竟写着麻烦写一次就够了。

在javaWeb开发中,基本用不到这样的单例,在spring,对象默认就是单例的,我们也不用这些方法去限制他只能产生一个对象,单例靠容器来控制,我们基本不手动产生对象。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值