企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
单例模式就是确保一个类只有一个实例,并且该实例必须自动创建,并向整个系统提供该实例。这样保证了对外的对象的属性等均为一个实例,就像是银行取款 单例模式原理图: ![](https://box.kancloud.cn/2016-07-12_578455cce0a88.png) 单例模式分为饿汉式单例模式和懒汉式单例模式。 饿汉式单例模式代码 ~~~ package com.designpattern.singleton; public class HungrySingleton { private HungrySingleton() { } private static HungrySingleton instance = new HungrySingleton(); public static HungrySingleton getInstance() { return instance; } } ~~~ 懒汉式单例模式代码 ~~~ package com.designpattern.singleton; public class LazySingleton { private LazySingleton() { } private static LazySingleton instance = null; public static synchronized LazySingleton getInstance() { if (instance == null) { instance = new LazySingleton(); } return instance; } } ~~~ 事例中对于饿汉式是不管外部有没有调用都new出了一个对象,二懒汉式只有在外部调用的时候,并且是第一次的时候才new出来对象的,但是一定要放在sychronized下面 这样感觉像是懒汉模式是在调用的时候分配空间初始化instance的,但是自己感觉上面两种是一样的效果 在实例化先后顺寻的角度分析:饿汉式类内static 对象会在构造器调用前初始化,也就是最先初始化,但是只初始化一次就不再初始化了,毕竟是static的,在构造器之前也就是只有在使用这个类的时候,才实例化。同时后者懒汉式中私有的static也会在构造器之前初始化,但是是null,这样就在第一次调用这个类的时候对instance进行了初始化,但是之后就不会再初始化了,原因也是static,这样看起来对于懒汉和饿汉的初始化和构造过程是一样的。 不过说道具体的地方饿汉式是在加载类的时候创建对象,而懒汉式是在调用getInstance时候创建对象,那么这样他们在创建的时候还是用一定的区别的。 下面借着这个Singleton模式简单的做了一个Log工具,实现对于一个日志工具不会多次初始化,并且不会覆盖掉而是尾加,Log4j就是一个Singleton的实例 ~~~ package com.designpattern.singleton; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.text.SimpleDateFormat; import java.util.Date; public class Log { private static final String DefalutLogFilePathName = System .getProperty("user.dir") + File.separator + "user.log"; private static Log log; private static PrintWriter pw; private Log() { pwinit(); } public static synchronized void log(String message) { if (log == null || pw == null) { log = new Log(); } if (pw != null) { pw.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") .format(new Date()) + " : " + message); } } public static void destroy() { log = null; if (pw != null) { pw.close(); } } private void pwinit() { if (pw == null) { try { pw = new PrintWriter(new FileWriter(DefalutLogFilePathName, true), true); } catch (IOException e) { e.printStackTrace(); pw = null; } } } } ~~~ 在Client端对Log进行操作,不会覆盖结果,测试成功 ~~~ package com.designpattern.singleton; public class Client { public static void main(String[] args) { System.out.print("Log"); System.out.print("\t"); Log.log("start"); Log.log("middle"); Log.log("end"); Log.destroy(); } } ~~~ 输出结果: ~~~ 2012-04-05 14:46:15 : start 2012-04-05 14:46:15 : middle 2012-04-05 14:46:15 : end ~~~ 在单例模式中,客户调用类的实例时,只能调用一个公共接口,这就是为整个开发团队提供了共享的概念。 但是但是模式的类在实例化以后,不能被别的类继承,在分布式系统中,当系统中的单例类被复制运行在多个虚拟机下时,在每一个虚拟机下都会创建一个实例对象,此时如果想知道具体那个虚拟机下运行着哪个单例对象是很困难的,而且单例类很难实现序列化。