单例模式就是确保一个类只有一个实例,并且该实例必须自动创建,并向整个系统提供该实例。这样保证了对外的对象的属性等均为一个实例,就像是银行取款
单例模式原理图:
单例模式分为饿汉式单例模式和懒汉式单例模式。
饿汉式单例模式代码
- 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;
- }
- }
这样感觉像是懒汉模式是在调用的时候分配空间初始化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
但是但是模式的类在实例化以后,不能被别的类继承,在分布式系统中,当系统中的单例类被复制运行在多个虚拟机下时,在每一个虚拟机下都会创建一个实例对象,此时如果想知道具体那个虚拟机下运行着哪个单例对象是很困难的,而且单例类很难实现序列化。