博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
design_model(1)singleton
阅读量:7049 次
发布时间:2019-06-28

本文共 3886 字,大约阅读时间需要 12 分钟。

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

 

转载于:https://www.cnblogs.com/gg128/p/9548164.html

你可能感兴趣的文章
iOS中根据已有经纬度定位并显示在地图上
查看>>
Git同时使用多个 ssh key
查看>>
hdu 2501
查看>>
findbugs错误类型对照表
查看>>
Eclipse代码补全,修改 空格键 "=" 键不上屏
查看>>
01背包问题的java界面实现
查看>>
[leetcode] Permutations
查看>>
查看Android应用包名package和入口activity名称
查看>>
jquery disabled设置不可编辑
查看>>
Java Base
查看>>
mysql优化sql语句查询的方法(一)
查看>>
既然存在,就是合理的
查看>>
【GIT-1】GIT 的基础教程 创建,添加,更替,追溯版本库
查看>>
【原创】公司自研缓存系统UPU的总结
查看>>
一个JavaScript的简单通用验证
查看>>
java面试基本数据类型考点
查看>>
百行 HTML5 代码实现四种双人对弈游戏
查看>>
jQuery.extend 函数详解
查看>>
phpstorm 安装 及 使用 去掉名称类型提示
查看>>
Xp sp3 创建进程的堆栈
查看>>