Java设计模式——单例模式

原创 2016年08月30日 11:24:12

简介

java中,有些对象我们只需要一个,比如:配置文件、线程池、日志对象等。如果创造出多个实例,就会导致很多问题,比如占用过多资源、不一致的结果等。

单例模式的实现方式有多种,万变不离其宗,单例模式的中心思想就是构造方法私有化。也就是说不允许在类的外部创造实例,那么类的实例从哪来?类自己提供,具体来说是类中的类方法提供。主要的实现方式有两种:恶汉模式和懒汉模式。

恶汉模式与懒汉模式

代码

/**
 * 单例模式测试类
 * @author Goser	(mailto:goskalrie@163.com)
 * @Since 2016年8月30日
 */
public class Singleton {
	
	public static void main(String[] args) {
		SingletonHungry sh1 = SingletonHungry.getInstance();
		SingletonHungry sh2 = SingletonHungry.getInstance();
		compare(sh1, sh2);//true
		SingletonLazy sl1 = SingletonLazy.getInstance();
		SingletonLazy sl2 = SingletonLazy.getInstance();
		compare(sl1, sl2);//true
	}
	
	public static <T> void compare(T obj1, T obj2){
		System.err.println(obj1==obj2);
	}
}
//恶汉模式
class SingletonHungry{
	//1.将构造方法私有化,不允许外部直接创建对象
	private SingletonHungry(){}
	//2.创建类的唯一实例
	private static SingletonHungry singletonHungry =new SingletonHungry();
	//3.提供一个用于获取实例的方法
	public static SingletonHungry getInstance(){
		return singletonHungry;
	}
}

//懒汉模式
class SingletonLazy{
	private SingletonLazy(){}
	private static SingletonLazy singletonLazy;
	public static SingletonLazy getInstance(){
		if(singletonLazy == null){
			singletonLazy = new SingletonLazy();
		}
		return singletonLazy;
	}
}

上面的测试代码中都打印出了true,说明单例模式是成功的。

从上面的代码中不难总结,实现单例模式的主要步骤:

1.构造方法私有化;

2.声明或创造实例;

3.提供实例的方法。

代码讲解:

第一步使用private关键字,将构造方法私有化,也就是说不允许外部实例化该类,好多资料都将单例模式和古代的皇帝进行比较,那么这一步就相当于中央集权。

第二步static声明或实例化,既然外部没有实例化的权利,但是类只要是想要使用,那么就需要实例化,总要有个人做这件事,这里有类本身进行实例化。

第三步将第二步的实例返回给调用getInsance方法的外部。

更进一步

以上三步,每一步都很重要,为什么使用上面的三步就能实现单例模式呢?前面说的单例模式的中心思想是构造方法私有化,但是,底层关键的是第二步的static关键字。static关键字的特点是,被static修饰的变量一般称为类变量,没有被static修饰的变量一般称为实例变量。从这点就能看出,类变量是与类对应的,类是唯一的,那么类变量也应该是唯一的。实际上,被static修饰的类变量,JVM只为静态分配一次内存,在加载类的过程中完成静态变量的内存分配,也就是说,类变量的内存是静止的(但是内存中的内容是可以改变的,就像是房子,房子盖好后不能再随便拆掉再盖,但是里面的人可以变)。由static关键字的特点可以得出,SingletonHungry中的singletonHungry变量SingletonLazy中的singletonLazy变量在内存中是唯一的,以此来实现单例,步骤一中的构造方法私有化是保障,步骤二中的static才是实现关键。

恶汉模式VS懒汉模式

恶汉与懒汉的命名由其实例化的时机而来。恶汉模式是在类加载的时候就实例化,形象的说就是,该种模式比较饥饿,需要先吃饱(实例化)才能工作,而懒汉模式则是在调用getInstance方法时才实例化,相较恶汉比较懒。

恶汉模式的特点是加载类时比较慢,但运行时获取对象的速度比较快(线程安全),因为在类加载时就实例化好了,已经与线程无关了。

懒汉模式的特点是加载类时比较快,但运行时获取对象的速度比较慢(线程不安全)

在实际使用时,一般两者区分很小,在对线程安全有要求时才会加以区别,或是使用其他的变体。但是面试的时候,基本上写出中心的步骤就可以了,如果能将static的底层关键表述出来,远比多说几种变体好的多。(面试的时候不一定面试官问你什么你就说什么,可以适当的明修栈道暗渡陈仓……声东击西,往往会得到意外的收货,但是相关性是第一的,问你java你不能回答C吧,但是问你单例模式的几种实现方式,你只还记得恶汉模式,那么回答完恶汉模式的实现肯定是不行的,会扣分的,但是补充上底层的实现,绝对是加分项)。

懒汉模式的线程安全改进

synchronized

线程安全是个专门的课程,一般的是使用同步synchronized关键字

//懒汉模式
class SingletonLazy{
	private SingletonLazy(){}
	private static SingletonLazy singletonLazy;
	public static synchronized  SingletonLazy getInstance(){
		if(singletonLazy == null){
			singletonLazy = new SingletonLazy();
		}
		return singletonLazy;
	}
有些资料上还会介绍什么双重检查,如:

//public static SingletonLazy getInstance() {  
//if (singletonLazy == null) {    
//  synchronized (SingletonLazy.class) {    
//     if (SingletonLazy == null) {    
//        SingletonLazy = new SingletonLazy();   
//     }    
//  }    
//}    
//return singletonLazy;   
//}
但是根本没什么用的,所以所有的代码注释掉了,没有什么实际的作用,还影响性能。

静态内部类方式

//静态内部类方式实现的单例模式
class SingletonLazy2 {    
    private static class LazyHolder {
       private static final SingletonLazy2 INSTANCE = new SingletonLazy2();
    }
    private SingletonLazy2(){}
    public static final SingletonLazy2 getInstance() {
       return LazyHolder.INSTANCE;
    }
}
这种方式,实际上是什么呢?将开始的代码做以下改变:

class SingletonLazy{
	private static class SingletonHungry {
		private static final SingletonLazy SINGLETONLAZY = new SingletonLazy();
	}
	private SingletonLazy(){}
	public static final SingletonLazy getInstance(){
		return SingletonHungry.SINGLETONLAZY;
	}
}
经过对比不难发现,所谓的静态内部类方式只不过是将恶汉模式作为懒汉模式的静态内部类来使用了,将懒汉和恶汉的优点结合起来,就成了即线程安全,又不影响性能的静态内部类模式了。

总结

单例模式基本有两种实现方式:恶汉模式和懒汉模式,恶汉模式线程安全,懒汉模式不安全,但是可以通过修改实现线程安全,单例模式还有其他的实现方式,但是常用的就是上面讲到的。



版权声明:本文为博主原创文章,未经博主允许不得转载。 举报

相关文章推荐

Java设计模式学习01——单例模式

转载自:http://blog.csdn.net/xu__cg/article/details/52902644 Java单例模式是一种常见且较为简单的设计模式。单例模式,顾名思义一个类仅能有一个实...

Java面向对象设计模式(三)——单例模式

单例对象(Singleton)是一种常用的设计模式。在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在。这样的模式有几个好处: 1、某些类创建比较频繁,对于一些大型的对象,这...

我是如何成为一名python大咖的?

人生苦短,都说必须python,那么我分享下我是如何从小白成为Python资深开发者的吧。2014年我大学刚毕业..

Java设计模式——单例模式

定义 保证一个类只有一个实例,并提供一个访问它的全局访问点,并且自行实例化向整个系统提供。 使用场景 当一个类的实例可以有且只可以一个的时候就需要用到了。为什么只需要有一个呢?一方面是为了减少...

学习笔记——JAVA设计模式<1>单例模式

Group of four GFO23种设计模式 创建型模式建对象 单例模式 工厂模式 抽象工厂模式 建造者模式原型模式 结构性模式 适配器模式 桥接模式 装饰模式 组合模式...

Java设计模式——单例模式

创建一个单例模式的步骤 1.构造方法私有化 2.自己创建一个唯一实例 3.提供一个静态的公共方法 一、懒汉式单例 /**  * @author My_chen  * @时间2016年...

Java设计模式——单例模式

单例设计模式(转)Singleton是一种创建型模式,指某个类采用Singleton模式,则在这个类被创建后,只可能产生一个实例供外部访问,并且提供一个全局的访问点。核心知识点如下:(1) 将采用单例...
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)