单例模式
-
懒汉模式
// 建议直接了解双重校验锁版本 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 class SingletonHolder{ private static SingletonDemo instance=new SingletonDemo(); } private SingletonDemo(){ System.out.println("Singleton has loaded"); } public static SingletonDemo getInstance(){ return SingletonHolder.instance; } }
-
枚举方法
enum SingletonDemo{ INSTANCE; public void otherMethods(){ System.out.println("Something"); } } // 调用 SingletonDemo.INSTANCE.otherMethods();
-
双重校验锁
public class SingletonDemo { // 这里volatile的作用是防止在instance = SingletonDemo()的时候指令重排列 // 1. 给instance 分配内存空间 // 重排列后 3.将给singleton对象指向分配的内存空间(此时singleton才不为null) // 2. 调用 Singleton 的构造函数来初始化成员变量 // 因为在3完成后,instance已经不==空了,这时候b线程进来就能直接返回instance // Synchronized锁代码块 private volatile 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; } }
单例模式实现的关键点:让对象在内存中只能有一份
-
可以使用静态类,将对象的代码放在虚拟机栈中;
-
可以在new 对象的时候判断对象是否已经存在,如果存在即返回对象即可,否则可以创造对象;如果是多线程环境还需要在判断对象不存在的时候,防止其他线程同时判断并创造对象,所以需要给对象上锁和保持可见性;
-
可以让对象在创建时就自己完成对象的创建;
静态类和单例的区别
1. 单例可以继承和被继承,方法可以被重写,而静态方法不可以。
2. 静态方法中产生的对象会在执行后被释放,进而被GC清理,不会一直存在于内存中。
3. 静态类会在第一次运行时初始化,单例模式可以延迟加载。
4. 基于2, 3条,由于单例对象往往存在于DAO层(例如sessionFactory),如果反复的初始化和释放,则会占用很多资源,而使用单例模式将其常驻于内存可以更加节约资源。
5. 静态方法有更高的访问效率。
6. 单例模式很容易被测试。
几个关于静态类的误解:
误解一:静态方法常驻内存而实例方法不是。
实际上,特殊编写的实例方法可以常驻内存,而静态方法需要不断初始化和释放。
误解二:静态方法在堆(heap)上,实例方法在栈(stack)上。
实际上,都是加载到特殊的不可写的代码内存区域中。
静态类和单例模式情景的选择:
情景一:不需要维持任何状态,仅仅用于全局访问,此时更适合使用静态类。
情景二:需要维持一些特定的状态,此时更适合使用单例模式。
-