单例模式的实现

单例的代码实现
懒汉模式

public class LazyInstance implements Serializable{
	private static LazyInstance instance;

	private LazyInstance(){

	}

	private static LazyInstance getInstance(){
		
				if(instance==null){
					instance=new LazyInstance();
				}
		return instance;
	}
}

弊端,会出现很多问题
1.多线程的问题:

public static void main(String[] args) throws Exception {

		//多线程问题
		for(int i=0;i<5;i++){
			new Thread(new Runnable() {
				@Override
				public void run() {
					System.out.println(Thread.currentThread().getName()+":"+LazyInstance.getInstance());
				}
			}).start();
		}
}

在这里插入图片描述
debugger后选择线程单步走
在这里插入图片描述
可以使用锁来解决,但是会出现性能的问题,这个可以加上二次检索来处理下:

private static LazyInstance getInstance(){
		if(instance==null){//二次检查
			synchronized (LazyInstance.class){
				if(instance==null){
					instance=new LazyInstance();
				}
			}
		}
		return instance;
	}

在这里插入图片描述
2.反射的问题:
接前面的代码

LazyInstance instance=LazyInstance.getInstance();
		Class clazz =LazyInstance.class;
		Constructor declaredConstructor = clazz.getDeclaredConstructor();
		declaredConstructor.setAccessible(true);
		Object obj = declaredConstructor.newInstance();
		System.out.println(instance);
		System.out.println(obj);

在这里插入图片描述
很容易出现反射攻击,可以在构造器中截个判断,存在过就抛出异常
3.序列化和反序列化

ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("singletonFile"));
        out.writeObject(instance);

        ObjectInputStream in = new ObjectInputStream(new FileInputStream("singletonFile"));

		LazyInstance newSingleton = (LazyInstance) in.readObject();

        System.out.println(newSingleton);

结果一样会出现多例的情况,这个其实可以复写readResolve方法来直接放回的,通过看read的源码可以发现,其实是通过反射newInstance了一个新的,后面重写后可以直接返回原来的覆盖,源码如下:

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())
        {
            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;
    }

在这里插入图片描述
重写:
在这里插入图片描述
饿汉模式

public class HuangrySingleton implements Serializable {

    private static HuangrySingleton instance = new HuangrySingleton();

    private HuangrySingleton(){
        if(instance !=null){
            throw new RuntimeException("禁止通过反射创建");
        }
    }

    public static HuangrySingleton getInstance(){
        return instance;
    }

    public Object readResolve(){
        return (Object) instance;
    }
}

通过枚举

public enum EnumSingleton {
    INSTANCE;



    public static  EnumSingleton getInstance(){
        return INSTANCE;
    }
}

容器

public class ContainerSingleton {

    private static HashMap<String,Object> map = new HashMap<String, Object>();

    private ContainerSingleton(){}

    public static void putInstace(String key,Object object){
        if(!StringUtils.isEmpty(key) && object !=null){
            map.put(key,object);
        }
    }

    public static Object getInstance(String key){
        return map.get(key);
    }
}

内部类:

public class StaticInnerClassSingleton {

    private static class InnerClass{
        static {
            System.out.println("innerclass");
        }
        private static StaticInnerClassSingleton
                instance = new StaticInnerClassSingleton();
    }

    private StaticInnerClassSingleton(){

    }

    public static StaticInnerClassSingleton getInstance(){
        System.out.println("getInstance");
        return InnerClass.instance;
    }

    public static void main(String[] args) {
        StaticInnerClassSingleton.getInstance();
    }
}

线程

public class ThreadLocalSingleton {

    private static ThreadLocal<ThreadLocalSingleton> threadLocal = new ThreadLocal(){
        @Override
        protected Object initialValue() {
            return new ThreadLocalSingleton();
        }
    };

    private ThreadLocalSingleton(){}

    public static ThreadLocalSingleton getInstance(){
        return threadLocal.get();
    }


    public static void main(String[] args) {
        System.out.println(ThreadLocalSingleton.getInstance());
        for(int i=0;i<5;i++){
            new Thread(new Runnable() {
                @Override
                public void run() {

                    System.out.println(Thread.currentThread().getName()+": "
                            +ThreadLocalSingleton.getInstance());
                }
            }).start();
        }
    }
}

等多种方式来生成,用的时候要注意多线程,序列化,和反射的问题!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值