实例探索Java模式之路——单例模式

单例模式


1、单例模式是对象的创建模式,单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。

这个类称为单例类。

2、单例模式特点:

  • 某个类只有一个实例

  • 它必须自行创建这个实例

  • 它必须自行向整个系统提供这个实例



3、单例模式中的单例类被限定只有一个实例,但单例模式和单例类可以很容易推广到任意且有有限个实例的情况,这时候就变成了多例模式和多例类。


4、饿汉式单例


饿汉式单例类是Java语言里实现最简单的单例类。在类初始化时已经自行实例化了。
 

public class eagersingleton {
    //初始化时已经自行实例化
    private static final eagersingleton m_instance = new eagersingleton();

    // 私有默认构造方法
    private eagersingleton() {

    }

    // 静态工厂方法
    public static eagersingleton getInstance() {
        return m_instance;
    }
}


特点:

  • 饿汉单例类在自己被加载时,静态变量m_instance就会被初始化,此时类的私有构造方法就会被调用,单例类的唯一实例就会被创建出来了。

  • 即便加载器是静态的,被加载时仍会将自己实例化。

  • Java单例类一个重要特点是类的构造方法是私有的,从而避免外界利用构造方法直接创建任意多的实例。

  • 此外,由于构造方法是私有的,所以此类不能被继承。

  • 天生是线程安全的。

  • 是比较符合Java语言本身。


5、懒汉式单例

懒汉式单例类的构造方法也是私有的。懒汉式单例类在第一次被引用时将自己实例化,如果加载器是静态的,那么懒汉式单例类被加载时不会将自己实例化。
只有当调用getInstance的时候,才回去初始化这个单例。
 

public class lazysingleton {
    private static lazysingleton m_instance = null;

    // 私有默认构造方法,外界无法直接实例化
    private lazysingleton() {

    }

    // 静态工厂方法
    synchronized public static lazysingleton getInstance() {
        if (m_instance == null) {
            //初始化这个单例
            m_instance = new lazysingleton();
        }
        return m_instance;
    }
}


静态工厂方法使用了同步化,以处理多线程环境。
由于构造方法是私有的,所以此类不能被继承。


6、登记式单例

是为了克服饿汉单例类和懒汉单例类均不能被继承的缺点而设计的。

public class regsingleton {
    static private HashMap m_registryHashMap = new HashMap();

    static {
        regsingleton regsingleton = new regsingleton();
        m_registryHashMap.put(regsingleton.getClass().getName(), regsingleton);
    }

    // 保护的构造方法,外界无法直接实例化
    protected regsingleton() {
        
    }
    
    // 静态工厂方法
    static public regsingleton getInstance(String name) {
        if (name == null) {
            name = "lazysingleton.regsingleton";
        }
        if (m_registryHashMap.get(name) == null) {
            try {
                m_registryHashMap.put(name, Class.forName(name).newInstance());
            } catch (Exception e) {
                System.out.println("error happened!");
            }
        }
        return (regsingleton) m_registryHashMap.get(name);
    }
    
    private String about() {
        return "hello world regsingleton";
    }
}


它的子类需要父类的帮助才能实例化。登记式单例类子类由父类将子类实例化。
 

public class regsingletonchild extends regsingleton {

    private regsingletonchild() {

    }

    /**
     * 静态工厂方法
     */
    static public regsingletonchild getInstance() {
        return (regsingletonchild) regsingleton
                .getInstance("lazysingleton.regsingletonchild");
    }

    private String about() {
        return "hello world regsingletonchild";
    }
}



7、单例使用场景

在一个系统要求一个类只有一个实例时才应当使用单例模式。

8、应用场景1:通过属性管理器例子深入理解

读取属性文件的单例类,作为单例模式的适用例子。
Singleton.properties

键=值
node1.item=hello
node2.item=1
node3.item=2
node4.item=3
node5.item=4
node7.item=5
node8.item=6
node9.item=world!

属性是一种资源,应避免多于一个的对象读取,特别是存储属性,属性文件管理器应当是由一个单例模式负责。

ConfigManager类有一个静态工厂getInstance用于提供自己的实例。

以饿汉方式实现的这个类:

public class ConfigManager {
    // 属性文件全名
    private static final String PFILE = System.getProperty("user.dir") + File.separator + "Singleton.properties";
    private File m_file = null;
    private long m_lastModiedTime = 0;
    private Properties m_props = null;
    // 存在的唯一的一个实例
    private static ConfigManager m_instance = new ConfigManager();

    // 私有构造方法,保证外界无法直接实例化
    private ConfigManager() {
        m_file = new File(PFILE);
        m_lastModiedTime = m_file.lastModified();
        if (m_lastModiedTime == 0) {
            System.err.println(PFILE + "file does not exist!");
        }
        m_props = new Properties();
        try {
            m_props.load(new FileInputStream(PFILE));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 静态工厂返回ConfigManager类的单一实例
    synchronized public static ConfigManager getInstance() {
        return m_instance;
    }

    // 读取一个特定的属性项
    final public Object getConfigItem(String name, Object defaultVal) {
        long newTime = m_file.lastModified();
        if (newTime == 0) {
            if (m_lastModiedTime == 0) {
                System.err.println(PFILE + "file does not exist!");
            } else {
                System.err.println(PFILE + "file was deleted!");
            }
            return defaultVal;
        } else if (newTime > m_lastModiedTime) {
            m_props.clear();
            try {
                m_props.load(new FileInputStream(PFILE));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        m_lastModiedTime = newTime;
        Object val = m_props.getProperty(name);
        if (val == null) {
            return defaultVal;
        } else {
            return val;
        }
    }
}


调用:

public class test {
    public static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        System.out.println("Type qiut to quit");
        do {
            System.out.println("Property item to read!");
            String line = reader.readLine();
            if (line.equals("quit")) {
                break;
            }
            System.out.println(ConfigManager.getInstance().getConfigItem(line, "Not found!"));
        } while (true);
    }
}


9、Java应用单例模式实例

  • Java的Runtime对象

  • Introspector类

  • Java.awt.Toolkit类


10、懒汉式单例例子:这个例子能更好的让我理解单例模式
 

public class lazysingleton {
    String name = null;
    private static lazysingleton m_instance = null;
    // 私有默认构造方法,外界无法直接实例化
    private lazysingleton() {
    
    }

    // 静态工厂方法
    synchronized public static lazysingleton getInstance() {
        if (m_instance == null) {
            m_instance = new lazysingleton();
        }
        return m_instance;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void printinfo() {
        System.out.println("name is " + name);
    }
}


普通的Java对象

public class nosingleton {
    String name = null;
    
    public String getName() {
        return name;
    }
    public nosingleton(String name) {
        this.name = name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void printinfo() {
        System.out.println("name is " + name);
    }
}


测试类:

public class test {
    public static void main(String[] args) {
        // 调用单例模式
        lazysingleton t1 = lazysingleton.getInstance();
        t1.setName("hello");
        lazysingleton t2 = lazysingleton.getInstance();
        t2.setName("world");

        //报错,私有默认构造方法,外界无法直接实例化
        // lazysingleton t3= new lazysingleton();
        t1.printinfo();
        t2.printinfo();

        if (t1 == t2) {
            System.out.println("创建的是同一个实例");
        } else {
            System.out.println("创建的不是同一个实例");
        }

        // 调用普通
        nosingleton nls1 = new nosingleton("第一次实例化");
        nosingleton nls2 = new nosingleton("第二次实例化");
        nls1.printinfo();
        nls2.printinfo();

        if (nls1 == nls2) {
            System.out.println("创建的是同一个实例");
        } else {
            System.out.println("创建的不是同一个实例");
        }
    }
}


输出结果:

name is world
name is world
创建的是同一个实例
name is 第一次实例化
name is 第二次实例化
创建的不是同一个实例

 

 

每天努力一点,每天都在进步。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

powerfuler

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值