学习笔记:单例模式

学习笔记:单例模式单例模式 单例模式是什么 有啥用 什么时候用 为什么要用 怎样用 先来一波素质五连 是什么 单例模式 字面上理解 单 一个 例 实例 也就是我们所说的对象有啥用 是为了资源的重复利用 只需要赋值或者初始化一次 大家就

大家好,欢迎来到IT知识分享网。

单例模式:单例模式是什么有啥用什么时候用为什么要用?怎样用?先来一波素质五连

是什么?

单例模式?字面上理解,单:一个,例:实例,也就是我们所说的对象

有啥用?

是为了资源的重复利用,只需要赋值或者初始化一次,大家就都能重复使用

什么时候用?为什么要用?(只有一份的如日历,只需要一份的如IOC容器)

Listener 监听器,Calender 日历类,IOC容器类,配置信息Config(一搬是单例)这些都是单例的

怎样用?(这个一句话说不了,容我细细道来)

下面我将用饿汉式,懒汉式,最牛逼单例模式,枚举,注册登记式反序列化如何保证单例 单例模式的运用形式进行详细说明

 

  1. 饿汉式(有处明显错误导致无法实现单例,答案暗藏在后文中)

学习笔记:单例模式

什么叫饿汉式?我的理解就是,饿了就迫不及待想吃,看下面第9行代码,声明为

private static final:说明类加载时就初始化就初始化对象,然后静态的,所以对象一直保存,直到程序停止

缺点:自然就是无论你用不用这个对象,在加载这个类的时候他都给你初始化了,都会占用空间,直到程序停止

优点:很明显,因为它在类被加载时就初始化,所以不存在对象创建时的并发问题,也就是不存在线程安全问题,可以保证单例,而且效率也算不错,因为当创建对象时需要的那几纳秒省了

建议应用场景:如果某个类的对象只需要一份,并且使用非常频繁,可以使用这种模式

 

  1. 懒汉式(明说了,答案就在下图)

学习笔记:单例模式

什么是懒汉式?我的理解就是,懒人特点了解下,什么事情都不急着提前准备,需要用时才去准备

我们可以看到,懒汉模式下的对象,我们可以在需要时再调用方法得到,并且能保证单例(能保证?)下面就来在优缺点里继续分析

优点:避免了内存的浪费,需要对象时才获得,而且非高并发时基本能保证单例

缺点:很明显,上面都说了非高并发时能保证单例,那么高并发时不能保证一定单例, 怎样解决呢,在方法前面加个synchronized关键字(如果对性能要求不高的话可加,毕竟同步锁要等待,不懂的可以去了解下同步锁synchronized)

  1. 既然上面或多或少都有缺点,下面再来个懒汉式改进版(也就是标题的最牛逼版,请不要叫我标题档…)

学习笔记:单例模式

优点:兼顾了饿汉模式的内存占用问题与synchronized的性能问题(性能我有测试,创建200W个对象速度跟饿汉模式基本没区别),测试代码就不贴了,自己动手试试

缺点:欢迎留言

注册式单利

注册式单例模式又称为等级式单例模式,就是将每一个实例都登记到某一个地方,使用唯一的标识获取实例。注册式单例i模式有两种:一种是枚举式单例模式,另一种是容器式单例模式。

1.枚举式单例模式

  枚举式单例模式写法如下:

复制代码

public enum EnumSingleton { INSTANCE; private Object data; public Object getData() { return data; } public void setData(Object data) { this.data = data; } public static EnumSingleton getInstance(){ return INSTANCE; } }

复制代码

  测试代码如下:

学习笔记:单例模式

复制代码

 @Test void EnumSingletonTest(){ EnumSingleton e1 = null; EnumSingleton e2 = EnumSingleton.getInstance(); e2.setData(new Object()); FileOutputStream fos = null; try { fos = new FileOutputStream("EnumSingleton.obj"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(e2); oos.flush(); oos.close(); FileInputStream fis = new FileInputStream("EnumSingleton.obj"); ObjectInputStream ois = new ObjectInputStream(fis); e1 = (EnumSingleton)ois.readObject(); ois.close(); System.out.println(e1.getData()); System.out.println(e2.getData()); System.out.println(e1.getData() == e2.getData()); } catch (Exception e) { e.printStackTrace(); } }

复制代码

  运行结果如下:

学习笔记:单例模式

  枚举类型其实通过类名和类对象找到一个唯一的枚举对象。因此,枚举对象不可能别类加载器加载多次。

  那么反射能否破坏枚举式单例模式呢?测试代码如下:

复制代码

 @Test void EnumSingletonTestThread() { try{ Class clazz = EnumSingleton.class; Constructor c = clazz.getDeclaredConstructor(); c.newInstance(); } catch (Exception e){ e.printStackTrace(); } }

复制代码

  运行结果如下:

学习笔记:单例模式

 报错没有找到无参构造方法。查看 Enum 源码  他的构造方法只有一个 protected 类型的构造方法,代码如下:

  protected Enum(String name, int ordinal){ this.name = name; this.ordinal = ordinal; }  

  再做如下测试:

复制代码

 @Test void EnumSingletonTestThread() { try{ Class clazz = EnumSingleton.class; Constructor c = clazz.getDeclaredConstructor(String.class,int.class); c.setAccessible(true); EnumSingleton enumSingleton = (EnumSingleton)c.newInstance("l-coil",666); } catch (Exception e){ e.printStackTrace(); } }

复制代码

   测试结果如下:

  学习笔记:单例模式

  报错已经很明显了,不能用反射来创建枚举类型。

  枚举式单例模式也是 Effective Java 书中推荐的一种单例模式实现写法。JDK 枚举的语法特殊性质及繁殖也为枚举报价护航,让枚举式单例模式成为一种比较优雅的实现。 

2.容器式单例

  容器式单例写法如下:

复制代码

public class ContainerSingleton { private ContainerSingleton(){} private static Map<String,Object> ioc = new ConcurrentHashMap<String,Object>(); public static Object getBean(String className){ synchronized (ioc){ if(!ioc.containsKey(className)){ Object obj = null; try{ obj = Class.forName(className).newInstance(); ioc.put(className, obj); }catch (Exception e){ e.printStackTrace(); } return obj; } else { return ioc.get(className); } } } }

复制代码

  容器式单例模式使用与实例非常多的情况,编辑管理。单它是非线程安全的。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/132889.html

(0)
上一篇 2025-07-27 21:33
下一篇 2025-07-27 21:45

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信