单例模式

  • 定义:保障一个类仅有一个实例,并提供一个全局拜访点
  • 类型:创立型
  • 实用场景:想确保任何状况下都相对只有一个实例
  • 长处:

    • 在内存里只有一个实例,缩小了内存开销
    • 能够防止对资源的多重占用
    • 设置全局拜访点,严格控制拜访
  • 毛病:没有接口,扩大艰难
  • 重点:

    • 公有结构器
    • 线程平安
    • 提早加载
    • 序列化和反序列化平安
    • 反射
  • Double Check

  • 动态外部类:

  • 实用技能

    • 反编译
    • 内存原理
    • 多线程Debug

  • 相干设计模式

    • 单例模式和工厂模式
    • 单例模式和享元模式
代码示例
懒汉式
public class LazySingleton {    private static LazySingleton lazySingleton;    private LazySingleton() {    }    /**     * synchronized(同步锁比拟耗费资源)     * 加在静态方法上:锁的是类的class文件     * 加在一般办法上:锁的是堆内存中的对象     * @return     */    public synchronized static LazySingleton getInstance(){//懒汉式        if(lazySingleton==null){            lazySingleton = new LazySingleton();        }        return lazySingleton;    }}
public class T implements Runnable{    @Override    public void run() {        LazySingleton lazySingleton = LazySingleton.getInstance();        System.out.println(Thread.currentThread()+" "+lazySingleton);    }}

测试类:

public class Test {    public static void main(String[] args) {//        LazySingleton lazySingleton = LazySingleton.getInstance();        Thread t1  = new Thread(new T());        Thread t2  = new Thread(new T());        t1.start();        t2.start();        System.out.println("program end");/*        for (int i = 0; i < 10; i++) {            new Thread(new T()).start();        }*/    }}

双重校验(改良):

public class LazyDoubleCheckSingleton {    // volatile多线程运行代码执行时重排序引起的问题(不容许重排序)    private volatile static LazyDoubleCheckSingleton lazyDoubleCheckSingleton;    private LazyDoubleCheckSingleton() {    }    public  static LazyDoubleCheckSingleton getInstance(){//懒汉式        if(lazyDoubleCheckSingleton==null){            synchronized (LazyDoubleCheckSingleton.class){                if (lazyDoubleCheckSingleton==null){                    lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton();                }            }        }        return lazyDoubleCheckSingleton;    }}

基于类初始化的提早加载解决方案:

/** * 基于类初始化的提早加载解决方案 */public class StaticInnerClassSingleton {    private StaticInnerClassSingleton() {    }    private static class InnerClass{        private static StaticInnerClassSingleton staticInnerClassSingleton = new StaticInnerClassSingleton();    }    public static StaticInnerClassSingleton getInstance(){        return InnerClass.staticInnerClassSingleton;    }}
public class T implements Runnable{    @Override    public void run() {//        LazySingleton lazySingleton = LazySingleton.getInstance();//        LazyDoubleCheckSingleton lazyDoubleCheckSingleton = LazyDoubleCheckSingleton.getInstance();        StaticInnerClassSingleton staticInnerClassSingleton = StaticInnerClassSingleton.getInstance();        System.out.println(Thread.currentThread()+" "+staticInnerClassSingleton);    }}
饿汉式
public class HungrySingleton {//饿汉式    // 申明为final的变量必须在类加载时实现赋值    private static final HungrySingleton hungrySingleton;    static{        hungrySingleton = new HungrySingleton();    }    private HungrySingleton() {    }    public static HungrySingleton getInstance() {        return hungrySingleton;    }}
序列化毁坏单例模式
public class HungrySingleton implements Serializable {//饿汉式    // 申明为final的变量必须在类加载时实现赋值    private static final HungrySingleton hungrySingleton;    static{        hungrySingleton = new HungrySingleton();    }    private HungrySingleton() {    }    public static HungrySingleton getInstance() {        return hungrySingleton;    }    /**     * 如果不写该办法,反序列化时会通过反射创立一个新的对象并返回,与序列化的对象不是同一对象。     * 若写了该办法,则反序列化时,尽管通过反射创立一个新的对象,但会返回该对象。     * @return     */    private Object readResolve(){        return hungrySingleton;    }}
public class Test {    public static void main(String[] args) throws IOException, ClassNotFoundException {        HungrySingleton instance = HungrySingleton.getInstance();        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singleton_file"));        oos.writeObject(instance);        File file = new File("singleton_file");        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));        HungrySingleton newInstance = (HungrySingleton) ois.readObject();        System.out.println(instance);        System.out.println(newInstance);        System.out.println(instance==newInstance);    }}
反射攻打解决方案
public class HungrySingleton implements Serializable {//饿汉式    // 申明为final的变量必须在类加载时实现赋值    private static final HungrySingleton hungrySingleton;    static{        hungrySingleton = new HungrySingleton();    }    private HungrySingleton() {        if (hungrySingleton!=null){            throw new RuntimeException("单例结构器禁止反射调用");        }    }    public static HungrySingleton getInstance() {        return hungrySingleton;    }}
public class StaticInnerClassSingleton {    private StaticInnerClassSingleton() {        if (InnerClass.staticInnerClassSingleton!=null){            throw new RuntimeException("单例结构器禁止反射调用");        }    }    private static class InnerClass{        private static StaticInnerClassSingleton staticInnerClassSingleton = new StaticInnerClassSingleton();    }    public static StaticInnerClassSingleton getInstance(){        return InnerClass.staticInnerClassSingleton;    }}
public class LazySingleton {    private static LazySingleton lazySingleton;    private LazySingleton() {        if (lazySingleton!=null){            throw new RuntimeException("单例结构器禁止反射调用");        }    }    public synchronized static LazySingleton getInstance(){//懒汉式        if(lazySingleton==null){            lazySingleton = new LazySingleton();        }        return lazySingleton;    }}

测试类:

/***能够解决饿汉式的反射攻打,但没有解决懒汉式的反射攻打。*/public class Test {    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {//        Class hungrySingletonClass = HungrySingleton.class;//        Class objectClass = StaticInnerClassSingleton.class;        Class objectClass = LazySingleton.class;        Constructor constructor = objectClass.getDeclaredConstructor();        constructor.setAccessible(true);//        HungrySingleton instance = HungrySingleton.getInstance();//        HungrySingleton newInstance  = (HungrySingleton) constructor.newInstance();//        StaticInnerClassSingleton instance = StaticInnerClassSingleton.getInstance();//        StaticInnerClassSingleton newInstance  = (StaticInnerClassSingleton) constructor.newInstance();        LazySingleton newInstance = (LazySingleton) constructor.newInstance();        LazySingleton instance = LazySingleton.getInstance();        System.out.println(instance);        System.out.println(newInstance);        System.out.println(instance==newInstance);    }}
Enum枚举单例

Jad:反编译工具

序列化

public class Test {    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {        //        HungrySingleton instance = HungrySingleton.getInstance();        EnumInstance instance = EnumInstance.getInstance();        instance.setData(new Object());        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singleton_file"));        oos.writeObject(instance);        File file = new File("singleton_file");        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));//        HungrySingleton newInstance = (HungrySingleton) ois.readObject();        EnumInstance newInstance = (EnumInstance) ois.readObject();        System.out.println(instance.getData());        System.out.println(newInstance.getData());        System.out.println(instance.getData()==newInstance.getData());    }}

反射

public enum EnumInstance {    INSTANCE{        protected void printTest(){            System.out.println("Feyl Print Test");        }    };    protected abstract void printTest();    private Object data;    public Object getData() {        return data;    }    public void setData(Object data) {        this.data = data;    }    public static EnumInstance getInstance(){        return INSTANCE;    }}
public class Test {    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {        Class objectClass = EnumInstance.class;        Constructor constructor = objectClass.getDeclaredConstructor(String.class,int.class);        constructor.setAccessible(true);        EnumInstance instance = (EnumInstance) constructor.newInstance("Feyl",666);        //        EnumInstance instance = EnumInstance.getInstance();//        instance.printTest();    }}
容器单例
public class ContainerSingleton {// 线程不平安    private static Map<String,Object> singletonMap = new HashMap<>();    private ContainerSingleton() {    }    public static void putInstance(String key, Object instance){        if (!StringUtils.isNotBlank(key)&&instance!=null){            if(!singletonMap.containsKey(key)){                singletonMap.put(key,instance);            }        }    }    public static Object getInstance(String key){        return singletonMap.get(key);    }}
public class T implements Runnable{    @Override    public void run() {        ContainerSingleton.putInstance("object",new Object());        Object instance = ContainerSingleton.getInstance("object");        System.out.println(Thread.currentThread()+" "+instance);    }}

测试类:

public class Test {    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {        Thread t1  = new Thread(new T());        Thread t2  = new Thread(new T());        t1.start();        t2.start();        System.out.println("program end");    }}
TreadLocal线程单例
public class ThreadLocalInstance {    private static final ThreadLocal<ThreadLocalInstance> threadLocalInstance            = new ThreadLocal<ThreadLocalInstance>(){        @Override        protected ThreadLocalInstance initialValue() {            return new ThreadLocalInstance();        }    };    private ThreadLocalInstance(){ }    public static ThreadLocalInstance getInstance() {        return threadLocalInstance.get();    }}
public class T implements Runnable{    @Override    public void run() {        ThreadLocalInstance instance = ThreadLocalInstance.getInstance();        System.out.println(Thread.currentThread()+" "+instance);    }}

测试类同上

“以空间换工夫”:ThreadLocal 为每一个线程创立一个空间,各个线程获取其独有的对象。