因程序需要,有时我们只需要某个类同时保留一个对象,不希望有更多对象,此时,我们则应考虑单例模式的设计。单例模式为一个面向对象的应用程序提供了对象惟一的访问点,不管它实现何种功能,整个应用程序都会同享一个实例对象。
- 饿汉式单例类
//饿汉式单例类.在类初始化时,已经自行实例化
2 public class Singleton1 {
3 //私有的默认构造子
4 private Singleton1() {}
5 //已经自行实例化
6 private static final Singleton1 single = new Singleton1();
7 //静态工厂方法
8 public static Singleton1 getInstance() {
9 return single;
10 }
11 }
不管使用使用都会加在,效率不高
- 懒汉模式
public class SingletonDemo {
private static SingletonDemo instance;
private SingletonDemo(){
}
public static SingletonDemo getInstance(){
if(instance==null){
instance=new SingletonDemo();
}
return instance;
}
}
如上,通过提供一个静态的对象instance,利用private权限的构造方法和getInstance()方法来给予访问者一个单例。
缺点是,没有考虑到线程安全,可能存在多个访问者同时访问,并同时构造了多个对象的问题。之所以叫做懒汉模式,主要是因为此种方法可以非常明显的lazy loading。
针对懒汉模式线程不安全的问题,我们自然想到了,在getInstance()方法前加锁,于是就有了第二种实现。
- 线程安全的懒汉模式
public class SingletonDemo {
private static SingletonDemo instance;
private SingletonDemo(){
}
public static synchronized SingletonDemo getInstance(){
if(instance==null){
instance=new SingletonDemo();
}
return instance;
}
}
然而并发其实是一种特殊情况,大多时候这个锁占用的额外资源都浪费了,这种打补丁方式写出来的结构效率很低。
- 双重校验锁法
public class SingletonDemo {
private static SingletonDemo instance;
private SingletonDemo(){
System.out.println("Singleton has loaded");
}
public static SingletonDemo getInstance(){
if(instance==null){
synchronized (SingletonDemo.class){
if(instance==null){
instance=new SingletonDemo();
}
}
}
return instance;
}
}
理论上双重校验锁法是线程安全的,并且,这种方法实现了lazyloading。
- 静态类内部加载
public class SingletonDemo {
private static class SingletonHolder{
private static SingletonDemo instance=new SingletonDemo();
}
private SingletonDemo(){
System.out.println("Singleton has loaded");
}
public static SingletonDemo getInstance(){
return SingletonHolder.instance;
}
}
使用内部类的好处是,静态内部类不会在单例加载时就加载,而是在调用getInstance()方法时才进行加载,达到了类似懒汉模式的效果,而这种方法又是线程安全的。
- 枚举方法
enum SingletonDemo{
INSTANCE;
public void otherMethods(){
System.out.println("Something");
}
}
Effective Java作者Josh Bloch 提倡的方式,在我看来简直是来自神的写法。解决了以下三个问题:
(1)自由序列化。
(2)保证只有一个实例。
(3)线程安全。
如果我们想调用它的方法时,仅需要以下操作:
public class Hello {
public static void main(String[] args){
SingletonDemo.INSTANCE.otherMethods();
}
}
综上所述枚举单例,是最优雅最简单的方式。
当然在实际开发中,需要根据具体业务选择具体实现方式。在具体业务中具体选择最合适的方案。