单例设计模式:保证对象 唯一性,创建对象时只能初始化一次对象,以后将只能调用第一次创建的对象,日后都将不能再次创建对象。
单列设计模式动机:
对于一个软件系统的某些类而言,我们无须创建多个实例。举个大家都熟知的例子——Windows任务管理器,如图3-1所示,我们可以做一个这样的尝试,在Windows的“任务栏”的右键弹出菜单上多次点击“启动任务管理器”,看能否打开多个任务管理器窗口?如果你的桌面出现多个任务管理器,我请你吃饭,(注:电脑中毒或私自修改Windows内核者除外)。通常情况下,无论我们启动任务管理多少次,Windows系统始终只能弹出一个任务管理器窗口,也就是说在一个Windows系统中,任务管理器存在唯一性。为什么要这样设计呢?我们可以从以下两个方面来分析:其一,如果能弹出多个窗口,且这些窗口的内容完全一致,全部是重复对象,这势必会浪费系统资源,任务管理器需要获取系统运行时的诸多信息,这些信息的获取需要消耗一定的系统资源,包括CPU资源及内存资源等,浪费是可耻的,而且根本没有必要显示多个内容完全相同的窗口;其二,如果弹出的多个窗口内容不一致,问题就更加严重了,这意味着在某一瞬间系统资源使用情况和进程、服务等信息存在多个状态,例如任务管理器窗口A显示“CPU使用率”为10%,窗口B显示“CPU使用率”为15%,到底哪个才是真实的呢?这纯属“调戏”用户,给用户带来误解,更不可取。由此可见,确保Windows任务管理器在系统中有且仅有一个非常重要。
回到实际开发中,我们也经常遇到类似的情况,为了节约系统资源,有时需要确保系统中某个类只有唯一一个实例,当这个唯一实例创建成功之后,我们无法再创建一个同类型的其他对象,所有的操作都只能基于这个唯一实例。为了确保对象的唯一性,我们可以通过单例模式来实现,这就是单例模式的动机所在。
//饿汉式
class Single
{
private static final Single s = new Single();
private Single(){}
public static Single getInstance()
{
return s;
}
}
//懒汉式 //为了实例的延迟加载,如果多线程访问时会出现安全问题。可以用同步来解决。不过有些低效。用双重判断可以解决低效。
class Single {
private static Single s = null;
private Single(){}
public static Single getInstance()
{
if(s==null)
s = new Single();
return s;
}
}
解决低效率代码://延迟加载的单例设计模式示例标准规范。
class Single {
private static Single s = null;
private Single(){}
public static Single getInstance()
{
if(s==null) //只判断一次将不在进来判断同步代码,加同步的时候使用的锁是该类所属的字节码文件对象。
{
synchronized(Sing.class) // 因为在静态方法中是无法使用this锁,所以只能使用该类所属的字节码文件对象(Sing.class)来作为锁。
if(s==null)
s = new Single();
return s;
}
}
}
懒汉式和饿汉式区别:
饿汉式:
public class Singleton{
private static Singleton singleton = new Singleton ();
private Singleton (){}
public Singleton getInstance(){return singletion;}
}
懒汉式:
public class Singleton{ //懒汉式在操作延迟加载时如果不加上synchronized会出现安全问题,懒汉式是一种延迟对象的加载。
private static Singleton singleton = null;
public static synchronized synchronized getInstance(){
if(singleton==null){
singleton = new Singleton();
}
return singleton;
}
}
比较:
饿汉式是线程安全的,在类创建的同时就已经创建好一个静态的对象供系统使用,以后不在改变
懒汉式如果在创建实例对象时不加上synchronized则会导致对对象的访问不是线程安全的,懒汉式如果加上synchronized会导致低效。可以使用双重if语句判断来避免每次运行synchronized造
成的低效。
推荐使用第一种