单例模式是指一个类只能有一个实例。单例模式可以避免实例的重复创建,全局访问的都是一个实例。创建单例模式大致思路就是将构造方法定义为私有,其他类不能实例化新的对象。创建单例模式有5种方式:
懒汉模式:
懒汉模式是常用的写法:
优点:
1、延迟加载。
缺点:
1、 在多线程情况下会存在问题,需要加同步关键字解决。但是同步后,性能会严重损耗。
2、可以通过反射重复建立实例。
class LazySingleton{
private static LazySingleton singleton=null;
private LazySingleton(){
}
public synchronized static LazySingleton getInstance(){
if(singleton==null){
singleton=new LazySingleton();
}
return singleton;
}
public String getName(){
return "fxt";
}
}
调用时:
String name =LazySingleton.getInstance().getName();
System.out.println(name);
反射破解步骤:
//获取构造方法
Constructorconstructor = Class.forName("singletonTest.single1").getDeclaredConstructor();
//可获取私有方法
constructor.setAccessible(true);
//获得实例
System.out.println(constructor.newInstance());
System.out.println(constructor.newInstance());
得到的两个实例是不一样的。
饿汉模式:优点:
1、由于加载类时就创建实例,所以线程安全(多个类加载器除外)。
缺点:
1、 没有达到延迟加载(懒加载)的效果。
2、可通过反射创建多个实例
class HungrySingleton{
private static HungrySingleton singleton=new HungrySingleton();
private HungrySingleton(){}
public static HungrySingleton getInstance(){
return singleton;
}
}
静态内部类:
优点:
加载时,不会初始化静态变量 INSTANCE,达到懒加载效果。class InternalSingleton{
private static class SingletonHolder{
private final static InternalSingleton INSTANCE=new InternalSingleton();
}
private InternalSingleton(){}
public static InternalSingleton getInstance(){
return SingletonHolder.INSTANCE;
}
}
枚举:
优点:
1、可以防止通过反射,多次创建对象。
2、线程安全
缺点:
1、失去类的一些特性
2、没有延迟加载
enum EnumSingleton{
INSTANCE;
public String getName(){
return "name";
}
}
调用时:
String name=EnumSingleton.INSTANCE.getName();
System. out.println(name);双重校验锁:
class LockSingleton{
private volatile static LockSingleton singleton;
private LockSingleton(){}
public static LockSingleton getInstance(){
if(singleton==null){
synchronized(LockSingleton.class){
if(singleton==null){
singleton=new LockSingleton();
}
}
}
return singleton;
}}
说明:
这种方法在JDK1.5之前是行不通的(1.5之后可以使用 volatile,这个关键字可以禁止重排序),因为JVM的重排序, singleton= new LockSingleton();代码在执行时,不一定按照a.初始化对象àb.实例化对象(调用构造方法)àc.将对象引用返回给 singleton,这个顺序,c有可能在b之前就运行,因此返回一个只初始化但是没有实例化的对象(不知理解的准确否???其他地方的实例化都有这种可能吗???),其他线程在判断singleton是否为null时,已经不为null了, 但是只是初始化没有实例化,这是就会出现问题。