设计模式(4)  -- 单例模式(Singleton)

试想一个读取配置文件的需求,创建完读取类后通过New一个类的实例来读取配置文件的内容,在系统运行期间,系统中会存在很多个该类的实例对象,也就是说系统中会同时存在多份配置文件的内容,这样会严重浪费内存资源。这样需要实现:在一个系统运行期间,只要一个类实例就可以了。

单例模式的定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

现在一个类能够被创建多个实例,问题的根源在于类的构造方法是公开的,也就是可以让类的外部通过构造方法创建多个实例。换句话说,只要类的构造方法能让类的外部访问,就没有办法去控制外部来创建这个类的实例个数。

要想控制一个类只被创建一个实例,那么首要的问题就是要把创建实例的权限收回来,让类自身来负责自己类实例的创建工作,然后由这个类来提供外部可以访问这个类实例的方法,这就是单例模式的实现方式。

在Java中,单例模式分为两种,懒汉式和饿汉式。

懒汉式:

public classSingletonLan {

privatestaticSingletonLan uniqueInstance = null;

privateSingletonLan(){

}

publicstaticsynchronizedSingletonLan getInstance(){

if(uniqueInstance==null){

uniqueInstancenew SingletonLan();

}

return uniqueInstance;

}

publicvoidsingletonOPeration(){

}

privateString singletonData;

publicStringgetSingletonData(){

return singletonData;

}

}

饿汉式:

public classSingletonE {

private static SingletonE uniqueInstance= newSingletonE();

privateSingletonE(){

}

publicstaticSingletonEgetInstance(){

return uniqueInstance;

}

publicvoidsingletonOPeration(){

}

privateString singletonData;

publicString getSingletonData(){

return singletonData;

}

}

Java里面实现的单例是一个虚拟机范围。因为装载类的功能是虚拟机的,所以一个虚拟机在通过自己的ClassLoader装载饿汉式实现单例类的时候就会创建一个类的实例。这就意味着如果一个虚拟机里面有很多个ClassLoader,而且这些ClassLoader都装载某个类的话,就算这个类是单例,它也会产生很多个实例。当然,如果一个机器上有多个虚拟机,那么每个虚拟机里面都应该至少有一个这个类的实例,也就是说整个机器上就有很多个实例,更不会是单例了。

单例模式的精粹是static变量在类装载的时候进行初始化;多个实例的static变量会共享同一块内存区域。

单例模式有一种应用叫延迟加载(Lazy Load):一开始不需要加载资源或者数据,一直等,等到马上要使用这个资源或者数据的时候才去加载。

利用缓存来实现单例模式:

import java.util.HashMap;

import java.util.Map;

public classSingletonCache {

private final static String DEFAULT_KEY="One";

private static Map<Object,SingletonCache> map = newHashMap<Object,SingletonCache>();

private SingletonCache(){

}

public static SingletonCache getInstance(){

SingletonCache instance = (SingletonCache)map.get(DEFAULT_KEY);

if(instance==null){

instance = new SingletonCache();

map.put(DEFAULT_KEY,instance);

}

return instance;

}

}

从线程安全上讲,懒汉式是线程不安全的,饿汉式是线程安全的(虚拟机保证只会加载一次,在装载类的时候是不会发生并发的),但是加了synchronized关键字的懒汉式是线程安全的,只是效率下降了。

可以使用双重检查加锁机制,指的是并不是每次进入getInstance方法都需要同步,而是先不同步,进入方法过后,先检查实例是否存在,如果不存在才进入下面的同步块,这是第一重检查。进入同步块后,再次检查实例是否存在,如果不存在,就在同步的情况下创建一个实例,这是第二重检查。这样一来,就只需要同步一次了。

双重检查加锁机制的实现用到关键字volatile,意思是被volatile修饰的变量的值,将不会被本地线程缓存,所有对该变量的读写都是直接操作共享内存,从而确保多个线程能正确的处理该变量。由于volatile关键字可能会屏蔽虚拟机中一些必要的代码优化,所以运行效率并不是很高。

public classSingletonVolatile {

privatevolatilestaticSingletonVolatile instance = null;

privateSingletonVolatile(){

}

publicstaticSingletonVolatilegetInstance(){

if(instance== null){

synchronized(SingletonVolatile.class){

if(instance==null){

instance = newSingletonVolatile();

}

}

}

return instance;

}

}

Lazyinitialization holder class模式综合实现了延迟加载和线程安全。在类加载的时候不去初始化对象。

public classSingletonClass {

privatestaticclassSingletonHolder{

private staticSingletonClass instance = newSingletonClass();

}

privateSingletonClass(){

}

publicstaticSingletonClassgetInstance(){

return SingletonHolder.instance;

}

}

据说单元素的枚举类型已经成为实现Singleton的最佳方法。

最新文章

  1. go 静态web服务器
  2. ruby on rails validates uniqueness
  3. 数组API
  4. Android--UI
  5. db2 中文表名和字段
  6. android 入门 002 (拨打电话,发送短信)
  7. Set-常用API及详解
  8. Android java.net.SocketException四大异常解决方案
  9. Centos6下yum安装MariaDB5.5(转)
  10. 学习Swift -- 构造器(中)
  11. chrome浏览器调试
  12. 多路复用I/O poll()
  13. C#代码控制 zip rar 解压缩
  14. Mysql高级之事务
  15. windows将某个应用加入开机启动项的解决办法
  16. 【一天一道LeetCode】#205. Isomorphic Strings
  17. java的方法重写 ,多态和关键字 instanceof和final
  18. 从0开始的Python学习001快速上手手册
  19. hive函数应用之操作json
  20. JAVA课程课后作业之使用递归完成回文

热门文章

  1. 弹出对话框 UIAlertController
  2. 转:Ext GridPanel根据条件显示复选框
  3. Ajax跨域访问问题-方法大全
  4. pgsql与mysql 下 varchar类型的数字文本的排序 区别
  5. Application_Start
  6. const变量与define定义常量的区别
  7. io开发之C语言第二天
  8. iOS:关于获取网络类型和运营商信息
  9. 重构第四天 : 用多态替换条件语句(if else &amp; switch)
  10. Linux Shell编程(22)——时间/日期 命令