单例模式那点事

一、单例模式

    1、饿汉式

/**
 * 饿汉式单例模式
 */
public class Singleton implements Serializable{
    //饿汉式 直接创建
    private static Singleton singleton = new Singleton();
    //构造器私有
    private Singleton(){
    }
    //提供一个静态方法来获取单例实例
    public static  Singleton getInstance(){
        return singleton;
    }
}

    2、懒汉式

/**
 * 懒汉式单例模式
 */
public class LazySingleton implements Serializable{
    //懒汉式 
    private static LazySingleton singleton = null;
    //构造器私有
    private LazySingleton(){
    }
    //提供一个静态方法来获取单例实例 先查看实例是否为null 如果为null 先创建,有的话直接返回
    public static LazySingleton getInstance(){
        if(singleton == null){
            singleton = new LazySingleton();
        }
        return singleton;
    }
}

二、单例模式改进

     1、缺点

       上面的两种单例模式,在单线程模式下是可以完整的运行的,但是在多线程环境中,可以会出现多个实例的情况出现,这就违背了单例的规则

    2、双重加锁机制

public class Singleton implement Serializable{
    private static Singleton singleton = null;
    //构造器私有
    private ProjectPoint(){
    }

    //DCL 双重校验
    public static synchronized ProjectPoint getInstance(){
        if(singleton == null){
            synchronized(ProjectPoint.class){
                if (singleton == null){
                    singleton =  new ProjectPoint();
                }
            }
        }
        return  singleton;
    }
}

   在类中获取实例使用了同步方法,和同步代码块的形式,在多线程中可以很好的避免了单例模式下获取多实例情况的出现。类似与采取了竞争资源(临界资源的同步)   

3、静态内部类

public class StaticSingleton implements Serializable{
    //构造器私有
    private StaticSingleton(){
    }

    public static synchronized StaticSingleton getInstance(){
        return  SingetonHolder.staticSingleton;
    }

    //使用静态内部类来获取实例
    /**
     * 这个实现思路中最主要的一点就是利用类中静态变量的唯一性
     */
    private static class SingetonHolder{
            private static final StaticSingleton staticSingleton = new StaticSingleton();
     }
    }
}

三、单例模式和序列化

    单例模式可能在序列化的形式下被破坏,序列化的其实会调用该对象的无参构造器,创建一个新的对象,代码如下:

@Test
    public void testSignton(){
        StaticSingleton singleton = StaticSingleton.getInstance();
        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:\\Users\\xieqixiu\\Desktop\\set.obj"))) {
            //对象序列化
            oos.writeObject(singleton);
        } catch (IOException e) {
            e.printStackTrace();
        }
        StaticSingleton singleton2 = null;
        //对象的反序列化
        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:\\Users\\xieqixiu\\Desktop\\set.obj"))) {
            singleton2 = (StaticSingleton) ois.readObject();
            //打印出来发现序列化的对象 和原来的对象不是同一个对象违背了单例模式唯一实例
            log.info( "projectPoint==projectPoint2 : {}",singleton==singleton2);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

 ois.readObject() 方法

  public final Object readObject()
        throws IOException, ClassNotFoundException
    {
        if (enableOverride) {
            return readObjectOverride();
        }

        // if nested read, passHandle contains handle of enclosing object
        int outerHandle = passHandle;
        try {
            //执行该方法获取对象 
            Object obj = readObject0(false);           
            }
}

 readObject0(false) 方法

 /**
     * Underlying readObject implementation.
     */
    private Object readObject0(boolean unshared) throws IOException {
        //省略部分代码
        depth++;
        totalObjectRefs++;
        try {
            switch (tc) {
                case TC_ENUM:
                    return checkResolve(readEnum(unshared));

                //执行该方法        
                case TC_OBJECT:
                    return checkResolve(readOrdinaryObject(unshared));
           //省略部分代码
    }

checkResolve()方法

 private Object readOrdinaryObject(boolean unshared)
        throws IOException
    {
        if (bin.readByte() != TC_OBJECT) {
            throw new InternalError();
        }

        ObjectStreamClass desc = readClassDesc(false);
        desc.checkDeserialize();

        Class<?> cl = desc.forClass();
        if (cl == String.class || cl == Class.class
                || cl == ObjectStreamClass.class) {
            throw new InvalidClassException("invalid class descriptor");
        }

        Object obj;
        try {
            //判断对象是否可以实例化,如果可以调用其中的无参构造器创建该对象实例
            obj = desc.isInstantiable() ? desc.newInstance() : null;
        } catch (Exception ex) {
            throw (IOException) new InvalidClassException(
                desc.forClass().getName(),
                "unable to create instance").initCause(ex);
        }

        passHandle = handles.assign(unshared ? unsharedMarker : obj);
        ClassNotFoundException resolveEx = desc.getResolveException();
        if (resolveEx != null) {
            handles.markException(passHandle, resolveEx);
        }

        if (desc.isExternalizable()) {
            readExternalData((Externalizable) obj, desc);
        } else {
            readSerialData(obj, desc);
        }

        handles.finish(passHandle);

        if (obj != null &&
            handles.lookupException(passHandle) == null &&
            desc.hasReadResolveMethod())
        {
            //调用该对象的实现的readResolve()方法 如果有的化   
            Object rep = desc.invokeReadResolve(obj);
            if (unshared && rep.getClass().isArray()) {
                rep = cloneArray(rep);
            }
            if (rep != obj) {
                // Filter the replacement object
                if (rep != null) {
                    if (rep.getClass().isArray()) {
                        filterCheck(rep.getClass(), Array.getLength(rep));
                    } else {
                        filterCheck(rep.getClass(), -1);
                    }
                }
                handles.setObject(passHandle, obj = rep);
            }
        }

        return obj;
    }

在readOrdinaryObject方法中由于调用了obj.newInstance() 会重新创建一个对象, 为了避免这种情况有一个invokeReadResolve()方法(该方法需要序列化的对象编写readResolve() 在该方法下重新返回这个对象信息即可保持序列化和反序列化的实例唯一)

最终代码如下:

//所有单例类 添加该方法
private Object readResolve() {
        return singleton;
    }

猜你喜欢

转载自blog.csdn.net/liushangzaibeijing/article/details/82714877