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

转载请注明出处:http://blog.csdn.net/myleike/article/details/50366705

看过关于单例模式的这么一个段子,大概是这样的:
俺有6个漂亮的老婆,她们的老公都是我,我就是我们家里的老公Singleton,她们只要说道“老公”,都是指的同一个人,那就是我(刚才做了个梦啦,哪有这么好的事)。好了,说正题。
**单例模式也就是确保一个类只有一个实例,并提供一个全局访问点。**

在许多设计中,一些对象其实我们只需要一个,比如说对话框、缓存等等。你可能会说:不是利用java全局的静态变量就可以做到吗?确实可以这样做,但是要将对象赋值给一个全局变量,那么必须在程序一开始就创建好对象,对吧?万一这个对象非常耗资源,但又长时间不会使用,不就成了一种浪费?这时单例模式就可以很好的解决这个问题。

**经典的单例模式**
/*-------------------Singleton.java---------------------*/
public class Singleton{
    //利用静态变量来记录Singleton的唯一实例
    private static Singleton singleton;
    //将构造方法声明为私有的,防止其他类随意调用
    private Singleton(){};
    //用getInstance()方法来实例化对象,并返回这个实例
    public static Singleton getInstance() {
        //对象为空时才对他进行实例化
        if(singleton==null) {
            System.out.println("创建了新的对象");
            singleton = new Singleton();
        }
        return singleton;
    }
}

/*--------------------Main.java----------------------*/
public class Main {
    public static void main(String[] args) {
        Singleton.getInstance();
        Singleton.getInstance();
        Singleton.getInstance();
    }
}

/*------------------执行结果-------------------------*/
创建了新的对象

我们看到不管调用了多少次getInstance()方法,singleton对象都只实例化了一次。那么在多线程中呢?我们修改一下Main.java

/*--------------------Main.java----------------------*/
public class Main {
    public static void main(String[] args) {
        new Thread(runnable).start();
        new Thread(runnable).start();
    }
    private static Runnable runnable = new Runnable() {
        public void run() {
            Singleton.getInstance();
        }
    };
}
/*------------------执行结果-------------------------*/
创建了新的对象
创建了新的对象

在多线程中,singleton被创建了多次。那我们加上同步呢?
懒汉式

/*-------------------Singleton.java---------------------*/
public class Singleton{
    .......
    public static synchronized Singleton getInstance() {
        ......
        return singleton;
    }
}
/*------------------执行结果-------------------------*/
创建了新的对象

问题确实得到了解决,但同步又会降低性能,又是一个新的问题。但是如果个体getInstance()的性能对你的应用程序不是很关键,那就忘了这件事吧,什么也别做。但是你要知道,同步一个方法可能造成程序执行效率下降100倍。

采用急切实例化,保证任何线程在访问getInstance()时,对象已经创建。
俄汉式

/*-------------------Singleton.java---------------------*/
public class Singleton{
    private static Singleton singleton = new Singleton();
    private Singleton(){};
    public static Singleton getInstance() {
        return singleton;
    }
}
/*------------------执行结果-------------------------*/
创建了新的对象

使用双重检测加锁减少getInstance()方法的同步。

/*-------------------Singleton.java---------------------*/
public class Singleton{
    ......
    public static Singleton getInstance() {
        if(singleton==null) {
            synchronized(Singleton.class) {
                //对象为空时才对他进行实例化
                if(singleton==null) {
                    System.out.println("创建了新的对象");
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}
/*------------------执行结果-------------------------*/
创建了新的对象

在这里,我们首先检查对象是否创建,如果没有创建才同步,这样就保证了只同步了一次。

以上四种就是常见的单例模式实现方法。哪在什么时候使用它们呢?它们各自的优缺点是什么呢?
经典模式:
很明显,这时最简单的一种方法,也有吧一个致命的错误,就是在多线程的情况下会创建多次对象。如果我们在不考虑使用多线程,就可以用它;
懒汉式:
这种方式能够解决多线程的问题,但是同步方法降低了性能。如果不考虑性能问题,就可以用它;
俄汉式:
这种方式在类加载时就创建了对象,使类加载变慢,虽然不是不是标准的单例模式,但还是解决了多线程的问题;
双重检测加锁:
这种方式解决了多线程问题,同时也解决了性能问题,但实现起来比较复杂。另外,采用该方法还得确定使用的是java5以上版本。

转载请注明出处:http://blog.csdn.net/myleike/article/details/50366705

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值