单例模式有很多实现方法,饿汉式、懒汉式、静态内部类、枚举类等等。
二、单例模式分类 一、饿汉式类加载时初始化,线程安全 。
优点:没有加锁,执行效率会提高。
缺点:类加载时就初始化,分配内存。
基于 classloader 机制避免了多线程的同步问题,
1、静态变量模式
//饿汉式(静态变量)
//加fianl主要是防止子类继承了之后对其修改
//
public final class Singleton implements Serializable{
//1. 构造器私有化, 外部能new
private Singleton() {
}
//2.本类内部创建对象实例
private final static Singleton instance = new Singleton();
//3. 提供一个公有的静态方法,返回实例对象
public static Singleton getInstance() {
return instance;
}
//4、防止反序列化时创建多个对象。当反序列化是,发现这个方法会使用这个方法所返回的对象,而不是会使用字节码生成的对象。
public Object readResolve(){
return instance;
}
//5、为什么提供静态方法而不是直接将private final static Singleton instance = new Singleton(); 设置为public。
//首先是提供public方法而不是设置为public会有更好的封装性,其次是方法还可以支持泛型,直接用成员变量没法支持泛型,最后是在创建单例对象时有更多的控制。
}
2、静态代码块模式
class Singleton {
//1. 构造器私有化, 外部能new
private Singleton() {
}
//2.本类内部创建对象实例
private static Singleton instance;
static { // 在静态代码块中,创建单例对象
instance = new Singleton();
}
//3. 提供一个公有的静态方法,返回实例对象
public static Singleton getInstance() {
return instance;
}
}
二、懒汉式
1、静态变量模式,有线程安全问题
class Singleton {
private static Singleton instance;
private Singleton() {}
//提供一个静态的公有方法,当使用到该方法时,才去创建 instance
//即懒汉式
public static Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
2、线程安全模式
// 懒汉式(线程安全,同步方法)
class Singleton {
private static Singleton instance;
private Singleton() {}
//提供一个静态的公有方法,加入同步处理的代码,解决线程安全问题,但是存在性能问题,不推荐使用
//即懒汉式
public static synchronized Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
3、推荐使用的三种模式
第一种:
public final class SingletonDemo {
//1.私有静态属性
private static volatile SingletonDemo singletonDemo= null;
//2.构造方法私有化
private SingletonDemo() {
}
public static SingletonDemo getSingletonDemo(){
//3.
if (singletonDemo == null){
synchronized (SingletonDemo.class){
if (singletonDemo == null){
//4.
singletonDemo = new SingletonDemo();
}
}
}
//5.
return singletonDemo;
}
}
第二种
// 静态内部类完成, 推荐使用
class Singleton {
private static volatile Singleton instance;
//构造器私有化
private Singleton() {}
//写一个静态内部类,该类中有一个静态属性 Singleton,类的加载也是懒惰的,只有用到的时候才会加载,也就是说没如果不调用下面的方法,这个类就不会加载
private static class SingletonInstance {
private static final Singleton INSTANCE = new Singleton();
}
//提供一个静态的公有方法,直接返回SingletonInstance.INSTANCE
public static synchronized Singleton getInstance() {
return SingletonInstance.INSTANCE;
}
}
第三种
public class SingletonTest08 {
public static void main(String[] args) {
Singleton instance = Singleton.INSTANCE;
Singleton instance2 = Singleton.INSTANCE;
System.out.println(instance == instance2);
System.out.println(instance.hashCode());
System.out.println(instance2.hashCode());
instance.sayOK();
}
}
//1.枚举单例是如何限制示例个数的?属性定义几个就有几个对象
//2.枚举单例在创建时是否有并发问题?没有,因为属性也是静态成员变量,在类加载器上完成的,是线程安全的
//3.枚举单例能否被反射破坏单例?不能
//4.枚举单例能否被反序列化破坏单例?不能,枚举父类实现了序列化接口,已经解决了反序列化破坏单例的问题
//5.枚举单例属于懒汉式还是饿汉式?饿汉式,属性也是属于静态成员变量,加载即创建对象
//6.枚举单例如果希望加入一些单例创建时的初始化逻辑该如何做?枚举也可以有构造方法,把逻辑加到构造方法中就可以了
//使用枚举,可以实现单例, 推荐
enum Singleton {
INSTANCE; //属性
public void sayOK() {
System.out.println("ok~");
}
}



