zoukankan      html  css  js  c++  java
  • design_model(1)singleton

    1.单例模式:单例模式指的是一个类只会有一个实例,即是instance,java web中Servlet就是单实例多线程的,单实例运用场景很多,例如在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例,单例的好处:节省内存,不需要new出来那么多实例;配合线程同步;一般用于公共资源。

    uml关系图:

    2.单例模式中设计的主要的问题:效率(同步影响效率),安全(线程安全),是否可延时(资源),是否可以避免反射和反序列化漏洞(枚举获取方式)

    3.饿汉式:线程安全,效率高,在类加载时初始化不能延时加载,如果没有调用赵成资源浪费

    //饿汉式:线程安全,效率高,在类加载时初始化不能延时加载,如果没有调用赵成资源浪费
    public class SingletonTest1 {
    	private static SingletonTest1 instance = new SingletonTest1();
    
    	private SingletonTest1() {
    
    	}
    
    	public static SingletonTest1 getInstance() {
    		return instance;
    	}
    }
    

     4.懒汉式:线程安全,因为可能需要并发操作所以效率不高,可以延迟加载避免资源浪费

    //懒汉式:线程安全,因为可能需要并发操作所以效率不高,可以延迟加载避免资源浪费
    public class SingletonTest2 {
    	private volatile static SingletonTest2 instance = null;
    
    	private SingletonTest2() {
    
    	}
    
    	public static SingletonTest2 getInstance() {
    		if (instance == null) {
    			synchronized (SingletonTest2.class) {
    				if (instance == null) {
    					return instance = new SingletonTest2();
    				}
    			}
    		}
    		return instance;
    	}
    }
    

     5.静态内部类获取:线程安全,效率高,可以延时加载

    //静态内部类获取方式:线程安全,效率高,可以延时加载
    public class SingletonTest3 {
    	private SingletonTest3() {
    
    	}
    
    	private static class createInstance {//类似静态方法
    		private static SingletonTest3 instance = new SingletonTest3();
    		static {//没有调用静态类不会输出
    			System.out.println(1111);
    		}
    	}
    	
    	public static SingletonTest3 getInstance() {
    		return SingletonTest3.createInstance.instance;
    	}
    	
    }
    

     6.枚举方式获取

    //枚举的方式获取:线程安全,效率高,不可以延时加载,可以避免方式和反序列化的路漏洞较为安全
    public enum SingletonTest4 {
    	instance;
    	public void test(){
    		
    	}
    }
    

     7.反射破解单例模式(非枚举)

    public class SingletonReflectTest {
       public static void main(String[] args) throws Exception {
    	   //除了枚举,其他类似
    	    Class<?> singletonClass = Class.forName("cn.singleton.test.SingletonTest1");
    	    Constructor<?> declaredConstructor = singletonClass.getDeclaredConstructor();
    	    declaredConstructor.setAccessible(true);
    	    SingletonTest1 instance = (SingletonTest1)declaredConstructor.newInstance();
    	    System.out.println(instance);
      }
    }
    

     防止破解方法(只能是饿汉式,对其余两种这种方法不行,初始化得到的对象和反射得到的对象不是同一个对象,假如先反射的话,就会有问题)

    private SingletonTest1()  {
    		if (instance != null) {
    			throw  new  RuntimeException();
    		}
    }
    

     8.反序列化破解//前提是实现了Serializable接口

    public class SingletonSerializable {
    	@SuppressWarnings("resource")
    	public static void main(String[] args) throws Exception {
    		SingletonTest1 instance = SingletonTest1.getInstance();
    		// jdk8新特性,能序列化需要实现Serializable接口
    		try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("a.txt"))) {
    			objectOutputStream.writeObject(instance);
    			System.out.println(instance);//cn.singleton.test.SingletonTest1@55f96302
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		Object readObject;
    		try (ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("a.txt"))) {
    			readObject = objectInputStream.readObject();
    			System.out.println(readObject);//cn.singleton.test.SingletonTest1@3d4eac69
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    }
    

     防止反序列化方法

    在序列化的方法中添加如下代码(重写readObject()方法)

    public SingletonTest1  readObject() {
    		return  instance;
    }
    

    9.上述几种单例模式的效率

    public class SingletonThread {
    	public static void test() {
    		// instant jdk 1.8新特性
    		CountDownLatch countDownLatch = new CountDownLatch(10);
    		long start = Instant.now().toEpochMilli();
    		for (int i = 0; i < 10; i++) {
    			new Thread(new Runnable() {
    				@Override
    				public void run() {
    					for (int i = 0; i < 10000000; i++) {
    						// SingletonTest1 47
    						// SingletonTest2 51
    						// SingletonTest3 47
    						// SingletonTest3 48
    						SingletonTest1 instance2 = SingletonTest1.getInstance();
    						// 枚举需要接受返回值否者报错
    //    					SingletonTest4 instance = SingletonTest4.instance;
    					}
    					countDownLatch.countDown();
    				}
    			}).start();
    		}
    		try {
    			countDownLatch.await();
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		long end = Instant.now().toEpochMilli();
    		System.out.println(end - start);
    	}
    
    	public static void main(String[] args) {
    		SingletonThread.test();
    	}
    }
    
  • 相关阅读:
    Electron中git, npm,webpack使用
    Luogu_2061_[USACO07OPEN]城市的地平线City Horizon
    Luogu_1080_国王游戏
    Luogu_2878_[USACO07JAN]保护花朵Protecting the Flowers
    GYOJ_1812_股票(stock)
    JXJJOI2018_三题
    JXJJOI2018_T3_catch
    JXJJOI2018_T1_market
    JXJJOI2018_T2_tank
    Luogu_2876_[USACO07JAN]解决问题Problem Solving
  • 原文地址:https://www.cnblogs.com/gg128/p/9548164.html
Copyright © 2011-2022 走看看