为什么选择单例模式?
单例模式主要是为了避免因为创建了多个实例造成资源的浪费,且多个实例由于多次调用容易导致结果出现错误,而使用单例模式能够保证整个应用中有且只有一个实例。从其名字中我们就可以看出所谓单例,就是单个实例也就是说它可以解决的问题是:可以保证一个类在内存中的对象的唯一性。
实现步骤
- 私有化该类的构造函数
- 通过new在本类中创建一个本类对象
- 定义一个公有的方法,将在该类中所创建的对象返回
单例模式的写法——饿汉式
//饿汉式
public class Singleton {
private static Singleton instance=new Singleton();
private Singleton(){};
public static Singleton getInstance(){
return instance;
}
}
//另一种饿汉式
public class Singleton{
private static Singleton instance = null;
static {
instance = new Singleton();
}
private Singleton() {};
public static Singleton getInstance() {
return instance;
}
}
- 访问方式
Singleton instance = Singleton.getInstance();
- 优点:
从它的实现中我们可以看到,这种方式的实现比较简单,在类加载的时候就完成了实例化,避免了线程的同步问题。
- 缺点:
由于在类加载的时候就实例化了,所以没有达到Lazy Loading(懒加载)的效果,也就是说可能我没有用到这个实例,但是它也会加载,会造成内存的浪费 (但是这个浪费可以忽略,所以这种方式也是推荐使用的)。
单例模式的写法——懒汉式(不推荐)
//懒汉式(线程不安全)
public class Singleton {
private static Singleton instance=null;
private Singleton() {};
public static Singleton getInstance(){
if(instance==null){
instance=new Singleton();
}
return instance;
}
}
- 问题:
有多个线程去调用getInstance方法来获取Singleton的实例,那么就有可能发生这样一种情况当第一个线程在执行if(instance==null)这个语句时,此时instance是为null的进入语句。在还没有执行instance=new Singleton()时(此时instance是为null的),第二个线程也进入if(instance==null)这个语句,因为之前进入这个语句的线程中还没有执行instance=new Singleton(),所以它会执行instance=new Singleton()来实例化Singleton对象。因为第二个线程也进入了if语句,所以它也会实例化Singleton对象。这样就导致了实例化了两个Singleton对象。所以单例模式的懒汉式是存在线程安全问题的。
单例模式的写法——懒汉式双重校验锁
public class Singleton {
/**
* 懒汉式变种,属于懒汉式中最好的写法,保证了:延迟加载和线程安全
*/
private static Singleton instance=null;
private Singleton() {};
public static Singleton getInstance(){
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
单例模式的写法——内部类
public class Singleton{
private Singleton() {};
private static class SingletonHolder{
private static Singleton instance=new Singleton();
}
public static Singleton getInstance(){
return SingletonHolder.instance;
}
}
单例模式的写法——枚举
public enum SingletonEnum {
instance;
private SingletonEnum() {}
public void method(){
}
}
- 访问方式
SingletonEnum.instance.method();
这代码,优雅,实在是太优雅了!