检查代码同上,运行结果同上。
饿汉模式
public class HungerSingleton {
private static final HungerSingleton singletoninstance = new HungerSingleton();
private Object data = new Object();
private HungerSingleton(){
}
public static HungerSingleton getInstance(){
return singletoninstance;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
在加载该类的时候就立马去实例化instance,不存在线程安全问题(由jvm保证线程安全问题),但是存在资源浪费、加载速度慢的问题。
检查代码同上,运行结果同上。
Holder模式
就是利用一个静态内部类来实现instance的实例化。这里利用了静态内部类的一个特性:该内部类的实例与外部类的实例 没有绑定关系,而且只有被调用到才会装载,从而实现了延迟加载
public class HolderSingleton {
private Object data = new Object();
private HolderSingleton(){
}
private static class InnerClass{
private static HolderSingleton singletoninstance = new HolderSingleton();
}
public static HolderSingleton getInstance(){
return InnerClass.singletoninstance;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
测试代码同上,运行结果同上。
在加载InnerClass的时候才会去实例化这个instance,实现了延迟加载,并且同饿汉模式一样,由jvm保证线程安全。这种方法值得推荐。
应用场景:
在整个系统中,只允许共用一个实例的类适合用单例模式来实现,比如:
网站的计数器,只允许存在一个计数器实例;
线程池,只允许存在一个线程池对象;
连接池,只允许存在一个连接池对象;
知识点扩充:
1.为什么要使用单例模式?
在我们日常的工作中,很多对象通常占用非常重要的系统资源,比如:IO处理,数据库操作等,那我们必须要限制这些对象只有且始终使用一个公用的实例,即单例。
2.单例模式的实现方式
构造函数私有化,防止其他类生成唯一公用实例外的实例。且单例类应该被定义为final,也就是说单例类不能被继承,因为如果允许继承那子类就都可以创建实例,违背了类唯一实例的初衷。
类中一个静态变量来保存单实例的引用。
一个共有的静态方法来获取单实例的引用。
3.单例模式的UML类图

4.单例模式的经典实现方式
饿汉式:一开始就创建好实例,每次调用直接返回,经典的“拿空间换时间”。 懒汉式:延迟加载,第一次调用的时候才加载,然后返回,以后的每次的调用就直接返回。经典“拿时间换空间”,多线程环境下要注意解决线程安全的问题。 登记式:对一组单例模式进行的维护,主要是在数量上的扩展,通过线程安全的map把单例存进去,这样在调用时,先判断该单例是否已经创建,是的话直接返回,不是的话创建一个登记到map中,再返回。









