目录
程序开发中有时候某些对象我们只需要一个,如:线程池、缓存、对话框等等,对于这类对象我们只能有一个实例,如果我们制造出多个实例,就会导致很多问题产生。但是我们怎样才能保证一个类只有一个实例并且能够便于访问?这里我们想到了全局变量,全局变量确实是可以保证该类可以随时访问,但是它很难解决只有一个实例问题。最好的办法就是让该自身来负责保存它的唯一实例。通过上面简单介绍,我们可以对单例模式有一个简单的认识。所谓单例模式就是确保某一个类只有一个实例,并且提供一个全局访问点。从上面可以看出单例模式有如下几个特点:1.它只有一个实例;2.它必须要自行实例化; 3.它必须自行向整个系统提供访问点。
单例的创建模式有很多种,下面的文章中我只介绍三种方式,多余的就不说了!
第一.饿汉式
/**
* 饿汉式天生就是线程安全的,可以直接用于多线程而不会出现问题
* @author Administrator
*
*/
public class Single1 {
private static final Single1 single1=new Single1();
private Single1() {
}
//静态工厂方法
public static Single1 getInstance(){
return single1;
}
}
第二.懒汉式
懒汉式本身是非线程安全的,为了实现线程安全有几种写法,分别是上面的下面的getInstance2和getInstance3,在资源加载和性能方面有些区别。
/**
* 懒汉式本身是非线程安全的,为了实现线程安全有几种写法,分别是上面的下面的getInstance2和getInstance3,在资源加载和性能方面有些区别。
* 还有一种方法是静态内部类,也是线程安全的
*/
public class Single2 {
private static Single2 single2=null;
Single2() {
}
/**
* 线程不安全
* @return
*/
public static Single2 getInstance(){
if(single2==null){
single2=new Single2();
}
return single2;
}
/**
* 在getInstance方法上加同步(性能较差)
* @return
*/
public static synchronized Single2 getInstance2(){
if(single2==null){
single2=new Single2();
}
return single2;
}
/**
* 双重检查锁定(DCL 双检查锁机制)推荐
* @return
*/
public static Single2 getInstance3(){
if(single2==null){
synchronized (Single2.class){
if(single2==null){
single2=new Single2();
}
}
}
return single2;
}
}
第三.静态内部类 推荐
利用静态内部类在原始类初始化的时候不加载的特性(只有在调用的时候才会加载),可以实现单例模式。
/**
* 静态内部类 推荐
*/
public class Single3 {
private static Logger logger= LoggerFactory.getLogger(Single3.class);
private static class CrateSingle{
private static final Single3 single3=new Single3();
}
private Single3() {
}
public static final Single3 getInstance(){
return CrateSingle.single3;
}
}
总结
优点
一、节约了系统资源。由于系统中只存在一个实例对象,对与一些需要频繁创建和销毁对象的系统而言,单例模式无疑节约了系统资源和提高了系统的性能。
二、因为单例类封装了它的唯一实例,所以它可以严格控制客户怎样以及何时访问它。
缺点
一、由于单例模式中没有抽象层,因此单例类的扩展有很大的困难。
二、单例类的职责过重,在一定程度上违背了“单一职责原则”。(因为单例设计模式,在代码getInstance书写的过程中,有些代码是比较复杂的,而且会伴有一些初始化的函数,会造成该类的多种初始化或者组装代码的书写。)
下列几种情况可以使用单例模式。
一、系统只需要一个实例对象,如系统要求提供一个唯一的序列号生成器,或者需要考虑资源消耗太大而只允许创建一个对象。
二、客户调用类的单个实例只允许使用一个公共访问点,除了该公共访问点,不能通过其他途径访问该实例。