一. 概念:
保证一个类仅有一个实例,并提供一个访问它的全局访问点,这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
二.要点:
- 某个类只能有一个实例
- 它必须自行创建这个实例
- 它必须自行向整个系统提供这个实例
三.优点:
- 在内存里只有一个实例,减少了内存的开销,避免频繁的创建和销毁实例
- 避免对资源的多重占用(比如写文件操作)。
四.缺点:
- 当一个单例的对象长久不用时,不会被jvm的垃圾收集机制回收
- 不能继承
五.常见使用场景
- 要求生产唯一序列号。
- WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。
- 创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。
六. 三种比较好的实现单例模式的写法:
1. 枚举 Enum (Java单例模式最佳实现方式)
public enum Singleton {
INSTANCE;
public void whateverMethod() {
System.out.println("Hello World!");
}
}
引用:
public class SingletonPatternDemo {
public static void main(String[] args) {
Singleton.INSTANCE.whateverMethod();
}
}
结果就输出Hello World!
用enum实现的好处:
1. 利用的枚举的特性实现单例
2. 由JVM保证线程安全
3. 序列化和反射攻击已经被枚举解决
调用方式为Singleton.INSTANCE, 出自《Effective Java》第二版第三条: 用私有构造器或枚举类型强化Singleton属性。(enum 在JDK1.5中加入)
2. 饿汉式
public class Singleton{
//类加载时就初始化
private static final Singleton instance = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return instance;
}
//可以根据需求特定函数
public void whateverMethod() {
System.out.println("Hello World!");
}
}
引用:
public class SingletonPatternDemo {
public static void main(String[] args) {
Singleton.getInstance().whateverMethod();
}
}
优点:线程安全,没有加锁,执行效率会提高。
缺点:它不是一种懒加载模式(lazy initialization) instance 在类装载时就被实例化,即使客户端没有调用 getInstance()方法,从而可能浪费了内存。饿汉式的创建方式在一些场景中将无法使用:譬如 Singleton 实例的创建是依赖参数或者配置文件的,在 getInstance() 之前必须调用某个方法设置参数给它,那样这种单例写法就无法使用了。
3. 内部静态类
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
//可以根据需求特定函数
public void whateverMethod() {
System.out.println("Hello World!");
}
}
引用:
public class SingletonPatternDemo {
public static void main(String[] args) {
Singleton.getInstance().whateverMethod();
}
}
优点:是一种懒加载模式(lazy initialization),避免了饿汉式instance 在类装载时就被实例化的问题 。因为 SingletonHolder 是私有的,除了 getInstance() 之外没有办法访问它,只有显示通过调用 getInstance 方法时,才会显示装载 SingletonHolder 类,这时而 instance才会被实例化。
七.总结什么情况下该用什么写法:
一般情况下直接使用饿汉式就好了,当明确要求要懒加载(lazy initialization)时则使用静态内部类,当涉及到反序列化创建对象时则使用枚举的方式来实现单例。
更多单例模式的写法推荐阅读:
http://www.runoob.com/design-pattern/singleton-pattern.html
转载请注明出处:
http://blog.csdn.net/fzw_faith/article/details/52887799