单例模式属于“创建型”模式,“创建型”模式主要讲对象的创建方法,单例模式有两种实现方式:饿汉式、懒汉式;下面对这两种实现方式加以总结。
1、饿汉式单例:
单例类在自己类内部定义自己的实现,注意构造函数的访问类型是private,这样外界没有创建单例类的方法,只能通过一个静态的getObj()方法来获得该单例的对象,而getObj()方法返回的对象是早已创建好的自身对象,无论调用多少次,返回的都是同一个对象,你可以通过set方法修改对象的属性值,但是reference引用指向的对象一直是同一个对象。
1 class Singleton{//可以用final修饰,也可以不用 2 private int val; 3 private static Singleton reference=new Singleton(23);//定义自己的实现 4 private Singleton(int val){ 5 this.val=val; 6 } 7 public static Singleton getObj(){ 8 return reference; 9 } 10 public void setVal(int val){ 11 this.val=val; 12 } 13 public int getVal(){ 14 return this.val; 15 } 16 }
2、懒汉式单例:
所谓“懒汉式”就是在我们需要单例对象的时候才给创建单例对象,而“饿汉式”是对象早已创建好了,已经等着我们去访问。问题出现了,我们可能“同时”需要单例对象,也就是多线程并发访问创建单例对象,这时候就需要控制一下了,因为单例对象只能创建一个,如果对创建方法不加控制,可能出现:A线程访问getObj()创建对象,还没来得及运行下面第九行的创建代码,cpu被B线程夺走,B也执行getObj()方法,并成功创建对象,cpu执行进程切换会记录断点,以便恢复后接着执行,所以A线程恢复运行后会接着执行第九行的创建代码,这时就产生了多个对象。为了防止以上情况的发生,我们可以控制线程对getObj()的访问情况,使它们一个个顺序执行,当A线程执行getObj()方法时,其他线程在一旁等着,如果reference指向为空就创建对象,反之直接返回,这样大家得到的对象就是第一次成功创建好的那个new Singleton(43)对象,这样就保证了对象的唯一性,满足了“单例”的要求。
1 class Singleton{//可以用final修饰,也可以不用 2 private int val; 3 private static Singleton reference=null; 4 private Singleton(int val){ 5 this.val=val; 6 } 7 synchronized public static Singleton getObj(){ 8 if(reference==null){ 9 reference=new Singleton(43); 10 } 11 return reference; 12 } 13 public void setVal(int val){ 14 this.val=val; 15 } 16 public int getVal(){ 17 return this.val; 18 } 19 }
注:以上内容是参看《Thinking in Patterns》后的总结结果,不足之处请大家多多指教。