单例模式:保证只有一个对象,每次获取对象获取到的都是同一个对象。
单例模式是我们程序中最常见的设计模式,很多工具类都设计成单例模式,spring中的bean也有单例,单他不是真正的单例。
单例模式总结下来有几种写法,他们共性就是私有的构造方法。
- 懒汉式
package com.designPattern.singleton;
/**
* 线程安全的 低效率的 懒加载
* 直接在方法上加互斥锁 synchronized 。简单粗暴
* 但是效率低。不加锁线程不安全,是错误代码
*/
public class SafeLazy {
private static SafeLazy safeLazy;
private SafeLazy(){};
public static synchronized SafeLazy getInstance(){
if(safeLazy==null){
return new SafeLazy();
}
return safeLazy;
}
- 饿汉模式
package com.designPattern.singleton;
/**
* 饿汉模式 由于太饿了就在初始化的时候创建对象。
* 饿汉模式是线程安全的,但是不适合单例的大对象。
* 或者是不常用的对象。
*/
public class Singleton {
private static Singleton singleton = new Singleton();
private Singleton(){};
public static Singleton getInstance(){
return singleton;
}
}
- (双重检查锁)线程安全的懒汉模式
package com.designPattern.singleton;
/**
* 双重校验锁
* 保证了线程的安全,
* 效率比方法上互斥锁要高效,适合并发。
* 当判断到没有实例化之后,
* 再加锁保证线程安全判断是否仍然没有实例化
*/
public class DoubleSafeLazy {
private static DoubleSafeLazy safeLazy ;
private DoubleSafeLazy (){}
public static DoubleSafeLazy getInstance(){
if(safeLazy == null ){
synchronized (DoubleSafeLazy.class){
if(safeLazy==null){
safeLazy = new DoubleSafeLazy();
}
}
}
return safeLazy;
}
}
- 内部类的方式
package com.designPattern.singleton;
/**
* 内部类的方式
* 借用了外部类装载的时候,内部类不装载的特性。
*/
public class InnerSingleton {
public static final InnerSingleton getInstance() {
return InnerSingletonBuilder.singleton;
}
private InnerSingleton (){}
private final static class InnerSingletonBuilder {
private static InnerSingleton singleton = new InnerSingleton();
}
}
- 枚举的方式
这种非常不常见,暂时不上代码。
另外有必要说一下spring的单例,spring的单例是在spring容器初始化的时候,会把bean对象创建好,放入上下文中,已一个map的形式存储, key 是bean的id,value是bean的实例对象。当每次取bean的实例的时候从map中获取,这样的单例是指的spring容器中的单例,不是真正的单例。