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设计模式之单例模式(几种写法及比较)

概念:   java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例、饿汉式单例、登记式单例。   单例模式有以下特点:   1、单例类只能有一个实例。  ...
  • tolcf
  • tolcf
  • 2015年10月21日 22:56
  • 6271

浅谈JAVA设计模式之——单例模式(Singleton)

一、概述        保证一个类仅有一个实例,并提供一个访问它的全局访问点。 二、适用性      1.当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。      2.当这个唯一...
  • l1028386804
  • l1028386804
  • 2015年05月02日 17:50
  • 1082

Java四种单例设计模式

Java中的四种单例模式单例模式是最容易理解的设计模式之一,介绍Java中单例模式的四种写法。1.饿汉式单例模式public class Singleton{ private static S...
  • twocold_2010
  • twocold_2010
  • 2016年11月20日 15:13
  • 271

浅谈常见设计模式--单例模式 简单工厂模式

今题那站在这里和大家一起分享最近在一本书上看到的关于设计模式的内容,接下来要讲的设计模式有: 单例模式 简单工厂模式 工厂方法和抽象工厂 代理模式 命令模式 策略模式 门面模式 桥接模式 观察者模式 ...
  • xikai18827083487
  • xikai18827083487
  • 2016年11月13日 17:04
  • 969

Java设计模式—单例模式

单例模式介绍: 单例模式(Singleton Pattern)是Java中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创...
  • ning421479924
  • ning421479924
  • 2017年06月11日 01:13
  • 119

java设计模式之单例模式5种方法及优缺点小结

单例设计模式的用处。单例设计模式是指,某个类只有一个实例。在计算机系统中类似于打印机和最常见的就是任务管理器的对话框,不管几个用户同时登录windows 打开的任务对话框只有一个。常见的几种实现方式:...
  • gwbbigbang
  • gwbbigbang
  • 2017年06月04日 18:27
  • 251

java面试题:java中的单例设计模式及两种实现方法的代码举例

java面试时经常会问到关于单例设计模式,因为它能考察的知识点较多且在开发中经常用到。 那我就来说一说我对于单例设计模式的一些浅见。 首先,在Java中,什么是单例呢? 就是保证类在内存中只有一...
  • qq_24693837
  • qq_24693837
  • 2016年11月23日 20:49
  • 1094

Java设计模式菜鸟系列(六)单例模式建模与实现

单例模式保证了一个类只有一个实例,且提供一个访问全局点的方式,更加灵活的保证了实例的创建和访问约束。系统中只有一个实例,因此构造方法应该为私有 饿汉式:类加载时直接创建静态实例;懒汉式:第一次需要时才...
  • JAVE_LOVER
  • JAVE_LOVER
  • 2014年10月05日 00:44
  • 2499

Java设计模式之一 单例设计模式

设计模式: 设计模式的概念首先来源于其它行业:建筑业,在早起建房子的时候,肯定是经验缺乏、显得杂乱无序的,这就会造成很多问题,在行业发展过程,通过不断的经验积累,前辈们针对这些问题提出了合理解决方案...
  • qq_32736689
  • qq_32736689
  • 2016年04月07日 08:29
  • 2270

设计模式系列(一)单例模式

一、简单介绍 单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中一个类只有一个实例。 《设计模式》书中对单例模式动机的介绍 对于系统中的某些类...
  • robertcpp
  • robertcpp
  • 2016年06月05日 11:00
  • 2227
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Java设计模式——单例模式
举报原因:
原因补充:

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