java设计模式之单例模式(一)

背景

单例模式是创建型的设计模式,在项目中大概率会用到,那么怎么用好单例模式呢,下面分别列出常见的一些单例模式写法,以及一些破坏单例模式的处理办法,供大家学习参考。

饿汉式

package com.example.pattern.hungry;

/**
 * 缺点:如果工程中饿汉式单例特别多,一些用不到的实例就比较浪费内存。
 */
public class HungryPattern {
    private static final HungryPattern hungryPattern = new HungryPattern();

    private HungryPattern() {

    }

    public static HungryPattern getInstance() {
        return hungryPattern;
    }

}

懒汉式写法1

package com.example.pattern.lazy;

/**
 * 懒汉式的优点:使用的时候才初始化实例,减少了不必要的内存浪费
 */
public class LazyPattern {
    //使用volatile是为了防止指令重排序
    private static volatile LazyPattern lazyPattern = null;

    private LazyPattern() {
        //防止反射破坏
        if (lazyPattern != null) {
            throw new RuntimeException("Not can use Construct Init...");
        }
    }


    public static LazyPattern getInstance() {
        if (lazyPattern == null) {
            synchronized (LazyPattern.class) {
                if (lazyPattern == null) {
                    lazyPattern = new LazyPattern();
                }
            }
        }
        return lazyPattern;
    }

}

懒汉式写法2

package com.example.pattern.lazy;

public class LazyStaticPattern {
    private LazyStaticPattern() {
        //防止反射破坏
        if (LazyStaticInner.lazyStaticPattern != null) {
            throw new RuntimeException("Not can use Construct Init...");
        }
    }

    public static LazyStaticPattern getInstance() {
        return LazyStaticInner.lazyStaticPattern;
    }

    private static class LazyStaticInner {
        private static final LazyStaticPattern lazyStaticPattern = new LazyStaticPattern();

    }
}

原理:静态内部类只有在显式调用时才会被 JVM 加载和初始化,因此实现了懒加载。
线程安全:由于类的初始化是由 JVM 管理的,因此在类初始化时是线程安全的
防止序列化破坏:但如果需要防止序列化破坏单例,可以重写 readResolve() 或 readObject() 方法来确保返回单例对象。

枚举类型单例

package com.example.pattern.register;

import org.omg.PortableInterceptor.INACTIVE;

public enum EnumPattern {
    INACTIVE;
    private Object object;

    public static EnumPattern getInstance() {
        return INACTIVE;
    }

}

单例放序列化攻击

package com.example.pattern.serialzable;

import com.example.pattern.lazy.LazyPattern;

import java.io.*;

public class SerializablePattern implements Serializable {
    private static SerializablePattern serializablePattern = new SerializablePattern();

    private SerializablePattern() {

    }

    public static SerializablePattern getInstance() {
        return serializablePattern;
    }


    //防止序列化破坏单例模式
    public Object readResolve() {
        if (serializablePattern != null) {
            return serializablePattern;
        }
        return null;
    }

    public static void main(String[] args) {
        SerializablePattern serializablePattern1 = SerializablePattern.getInstance();
        try {
            //先将对象以字节码的方式写入到文件中
            FileOutputStream fos = new FileOutputStream(new File("serializable.obj"));
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(fos);
            objectOutputStream.writeObject(serializablePattern1);
            System.out.println(serializablePattern1.toString());
            //再从文件中读取字节码文件转成对象
            FileInputStream fis = new FileInputStream(new File("serializable.obj"));
            ObjectInputStream objectInputStream = new ObjectInputStream(fis);
            SerializablePattern serializablePattern2 = (SerializablePattern) objectInputStream.readObject();
            System.out.println(serializablePattern2.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

注意:

还可以使用ioc和threadlocal进行单例的获取,分别具有不同的特点,由于篇幅较多,这里就不做说明了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值