单例模式-创建型

定义:

保证一个类仅有一个实例,并提供一个全局访问点


适应场景:

想确保任何情况下都绝对只有一个实例
如:网站的计数器、线程池、数据库的连接池...


优点:

在内存里只有一个实例,减少了内存开销;
可以避免对资源的多重占用;
设置全局访问点,严格控制访问。


缺点:

没有接口,扩展困难;

重点:

私有构造器;线程安全;延迟加载;序列化和反序列化安全问题(重要);防止反射攻击(重要)。

代码示例:

1.饿汉式

方式1:

package com.demo.design_pattern.creational.singleton;

import java.io.Serializable;

/**
 * HungrySingleton
 *
 * @Description 饿汉式单例模式
 */
public class HungrySingleton implements Serializable {
    private static final HungrySingleton hungrySingleton = new HungrySingleton();

    private HungrySingleton() {
        //防止单例反射攻击代码
        if (hungrySingleton != null) {
            throw new RuntimeException("单例构造器禁止反射调用");
        }
    }

    public static HungrySingleton getInstance() {
        return hungrySingleton;
    }

    private Object readResolve() {
        return hungrySingleton;
    }
}

方式2:

package com.demo.design_pattern.creational.singleton;

import java.io.Serializable;

/**
 * HungrySingleton
 *
 * @Description 饿汉式单例模式
 */
public class HungrySingleton implements Serializable {
    
    // 放在静态代码块中
    private static HungrySingleton hungrySingleton = null;

    static {
        hungrySingleton = new HungrySingleton();
    }

    private HungrySingleton() {
        //防止单例反射攻击代码
        if (hungrySingleton != null) {
            throw new RuntimeException("单例构造器禁止反射调用");
        }
    }

    public static HungrySingleton getInstance() {
        return hungrySingleton;
    }

    private Object readResolve() {
        return hungrySingleton;
    }
}

2.懒汉式

package com.demo.design_pattern.creational.singleton;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * LazySingleton
 *
 * @Description 懒汉式单例模式   注重延迟加载
 */
public class LazySingleton {

    private static LazySingleton lazy = null;

    private LazySingleton() {
        if (lazy != null) {
            throw new RuntimeException("单例构造器禁止反射调用");
        }
    }

    public synchronized static LazySingleton getInstance() {
        if (lazy == null) {
            lazy = new LazySingleton();
        }
        return lazy;
    }


}

3.懒汉式双重校验

package com.demo.design_pattern.creational.singleton;

/**
 * LazyDoubleCheckSingleton
 *
 * @Description 懒汉式双重校验单例模式
 */
public class LazyDoubleCheckSingleton {
    //volatile 保证所有线程可见性
    private volatile static LazyDoubleCheckSingleton lazyDoubleCheckSingleton = null;

    private LazyDoubleCheckSingleton() {
    }

    public static LazyDoubleCheckSingleton getInstance() {
        if (lazyDoubleCheckSingleton == null) {
            synchronized (LazyDoubleCheckSingleton.class) {
                if (lazyDoubleCheckSingleton == null) {
                    lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton();
                    //1.分配内存给这个对象
                    //2.初始化对象
                    //3.设置 lazyDoubleCheckSingleton 指向刚分配的内存地址
                }
            }
        }
        return lazyDoubleCheckSingleton;
    }
}

4.基于容器实现单例模式

package com.demo.design_pattern.creational.singleton;

import org.apache.commons.lang3.StringUtils;

import java.util.HashMap;
import java.util.Map;

/**
 * ContainerSingleton
 *
 * @Description 容器单例模式
 */
public class ContainerSingleton {
    //map看作一个容器
    private static Map<String, Object> singletonMap = new HashMap<>();

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


}

5.基于枚举实现单例模式

package com.demo.design_pattern.creational.singleton;

/**
 * EnumInstance
 *
 * @Description 使用枚举实现单例模式
 * 主要关注:枚举类型的序列化机制、反射攻击
 */
public enum EnumInstance {
    INSTANCE {
        @Override
        protected void printTest() {
            System.out.println("Geely 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;
    }
}

6.静态内部类单例模式

package com.demo.design_pattern.creational.singleton;

/**
 * StaticInnerClassSingleton
 *
 * @Description 静态内部类单例模式
 */
public class StaticInnerClassSingleton {

    private static class InnerClass {
        private static StaticInnerClassSingleton staticInnerClassSingleton = new StaticInnerClassSingleton();
    }

    public static StaticInnerClassSingleton getInstance() {
        return InnerClass.staticInnerClassSingleton;
    }

    private StaticInnerClassSingleton() {
        if (InnerClass.staticInnerClassSingleton != null) {
            throw new RuntimeException("静态内部类方式 防止反射攻击单例模式");
        }
    }
}

7.基于ThreadLocal的单例模式

package com.demo.design_pattern.creational.singleton;

/**
 * ThreadLocalInstance
 *
 * @Description 基于ThreadLocal的单例模式
 */
public class ThreadLocalInstance {

    private static final ThreadLocal<ThreadLocalInstance> threadLocalInstanceThreadLocal = new ThreadLocal<ThreadLocalInstance>() {

        @Override
        protected ThreadLocalInstance initialValue() {
            return new ThreadLocalInstance();
        }
    };

    private ThreadLocalInstance() {

    }

    public static ThreadLocalInstance getInstance() {
        return threadLocalInstanceThreadLocal.get();
    }


}

8.测试

(1)定义线程类

package com.demo.design_pattern.creational.singleton;

/**
 * MyThread
 *
 * @Description
 */
public class MyThread implements Runnable {
    @Override
    public void run() {
         LazySingleton instance = LazySingleton.getInstance();
        // LazyDoubleCheckSingleton instance =   LazyDoubleCheckSingleton.getInstance();
        //StaticInnerClassSingleton instance =  StaticInnerClassSingleton.getInstance();
        // HungrySingleton instance = HungrySingleton.getInstance();
       /* ContainerSingleton.putInstance("object",new Object());
        Object object = ContainerSingleton.getInstance("object");*/
        //ThreadLocalInstance instance = ThreadLocalInstance.getInstance();
        System.out.println("&&&&&&&&&&&&&&&" + Thread.currentThread().getName() + ":" + instance);
    }
}

(2)测试懒汉式单例模式

package com.demo.design_pattern.creational.singleton;

/**
 * SingletonTest
 *
 * @Description
 */
public class SingletonTest {

    public static void main(String[] args) throws Exception {
         System.out.println("**************测试懒汉式单例模式start");
        // LazySingleton instance = LazySingleton.getInstance();
        //多线程测试懒汉式单例模式
        Thread t1 = new Thread(new MyThread());
        Thread t2 = new Thread(new MyThread());
        t1.start();
        t2.start();
         System.out.println("**************测试懒汉式单例模式end");

    }

}

测试结果

(3)测试 使用序列化或反序列化破坏单例模式

package com.demo.design_pattern.creational.singleton;

import java.io.*;

/**
 * SingletonTest
 *
 * @Description
 */
public class SingletonTest {

    public static void main(String[] args) throws Exception {
    
        //使用序列化或反序列化破坏单例模式
        HungrySingleton hungrySingleton = HungrySingleton.getInstance();
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singleton_file"));
        oos.writeObject(hungrySingleton);
        File singleton_file = new File("singleton_file");
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(singleton_file));
        HungrySingleton newInstance = (HungrySingleton) ois.readObject();
        System.out.println("!!!!!!!" + hungrySingleton);
        System.out.println("!!!!!!!" + newInstance);
        System.out.println("hungrySingleton == newInstance 为"+ (hungrySingleton == newInstance));
      
    }

}

测试结果:

(4) 饿汉式 反射攻击解决方案

package com.demo.design_pattern.creational.singleton;

import java.io.*;
import java.lang.reflect.Constructor;

/**
 * SingletonTest
 *
 * @Description
 */
public class SingletonTest {

    public static void main(String[] args) throws Exception {
       
        // 饿汉式 反射攻击解决方案
        Class hungrySingletonClass = HungrySingleton.class;
        Constructor constructor = hungrySingletonClass.getDeclaredConstructor();
        constructor.setAccessible(true);
        HungrySingleton instance = HungrySingleton.getInstance();
        HungrySingleton newInstance =(HungrySingleton) constructor.newInstance();
        System.out.println("!!!!!!!" + instance);
        System.out.println("!!!!!!!" + newInstance);
        System.out.println(instance == newInstance);
    
    }

}

(5)静态内部类方式 防止反射攻击

package com.demo.design_pattern.creational.singleton;

import java.io.*;
import java.lang.reflect.Constructor;

/**
 * SingletonTest
 *
 * @Description
 */
public class SingletonTest {

    public static void main(String[] args) throws Exception {
       
        //静态内部类方式 防止反射攻击
        Class staticInnerClassSingletonClass = StaticInnerClassSingleton.class;
        Constructor constructor = staticInnerClassSingletonClass.getDeclaredConstructor();
        constructor.setAccessible(true);
        StaticInnerClassSingleton newInstance = (StaticInnerClassSingleton)constructor.newInstance();
        StaticInnerClassSingleton instance = StaticInnerClassSingleton.getInstance();
    
    }

}

(6)使用懒汉式 防止反射攻击

package com.demo.design_pattern.creational.singleton;

import java.io.*;
import java.lang.reflect.Constructor;

/**
 * SingletonTest
 *
 * @Description
 */
public class SingletonTest {

    public static void main(String[] args) throws Exception {
       
        //使用懒汉式 防止反射攻击
        Class objectClass = LazySingleton.class;
        Constructor constructor = objectClass.getDeclaredConstructor();
        constructor.setAccessible(true);
        LazySingleton newInstance = (LazySingleton)constructor.newInstance();
        LazySingleton instance =  LazySingleton.getInstance();
        System.out.println("!!!!!!!" + instance);
        System.out.println("!!!!!!!" + newInstance);
        System.out.println(instance == newInstance);
    
    }

}

测试结果:

(7)枚举测试序列化机制

package com.demo.design_pattern.creational.singleton;

import java.io.*;
import java.lang.reflect.Constructor;

/**
 * SingletonTest
 *
 * @Description
 */
public class SingletonTest {

    public static void main(String[] args) throws Exception {
       //枚举测试序列化机制
        EnumInstance enumInstance = EnumInstance.getInstance();
        enumInstance.setData(new Object());
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singleton_file"));
        oos.writeObject(enumInstance);
        File singleton_file = new File("singleton_file");
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(singleton_file));
        EnumInstance newInstance = (EnumInstance) ois.readObject();
        System.out.println("!!!!!!!" + enumInstance.getData());
        System.out.println("!!!!!!!" + newInstance.getData());
        System.out.println(enumInstance.getData() == newInstance.getData());
    
    }

}

测试结果:

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值