设计模式之单例模式

我在看开源代码时,时不时会惊叹,这怎么写的。那么完美,层层递进,行云流水,我什么时候才能写出这样诗画般的代码。


接着我就踏上了设计模式的学习之路。设计模式很多,比如抽象工厂模式,建造者模式,装饰模式,观察者模式,适配器模式,单例模式等等

 

第一弹,设计模式之单例模式

 

单例模式是设计模式中最简单的,最简单的,最简单的

 

单例模式的意义:

我们现在想像一个场景  :  有一个打印机类,物理硬件就只有一个,(哈哈。我们实验室就只有一台打印机。)如果在多个地方new出实例,并且是同时执行打印操作,那么打印出来的东西,就不仅仅是你的东西了,可能上面是别人的,紧接着才是你的,也就是东西会混在一起。

 

这种情况,一个类的对象只需要一个,如果有多个实例会造成冲突

 

单例模式就是确保一个类只有一个实例,并提供一个全局访问点

 

可以参考下图


Singleton类,有一个static静态变量uniqueInstance;私有的构造方法,和静态的getInstance()方法

 

这里封闭了构造方法,那么外部就无法使用构造方法来产生实例了。接着getInstance()这个提供给外部调用的静态方法用于获取唯一的实例uniqueInstance

 

一个很标准的单例模式模型代码如下


public class Singleton{
       private static Singleton singleton = null;
 
       private SingleTon(){
 
       };
 
       public static Singleton getInstance(){
 //这里先判断singleton实例是否存在,如果不存在,表明还没有创建过这个类的实例,接着就执行if语句的逻辑new出一个实例。如果已经存在,表明已经创建过实例了,依据单例模式原理,直接返回全局的静态singleton即可
           if (singleton == null){
                singleton = new Singleton();
           }else {
                return singleton;
           }
       }
    }




接下来进行代码演示,巧克力工厂项目

 

public class ChocolateFactory{
 
       //标记锅里材料是否为空
       private boolean empty;
       //标记是否煮沸
private boolean boiled;
 
       public ChocolateFactory(){
           empty = true;
           boiled = false;
       }
             
       //填满材料
       public void fill(){
           if(empty){
                empty = false;
                boiled = false;
           }
       }

       //倒出煮沸的巧克力
       public void drain(){
           if((!empty)&&boiled){
                empty   = true;
           }
       }
 
 
       //煮沸
       public void boid(){
           if((!empty)&&(!boiled)){
                boiled = true;
           }
       }
 
}


就一个大锅用来煮巧克力,假设创建了两个巧克力工厂对象,当一个对象执行装满巧克力材料方法后,另一个对象再次调用,此时empty已经被赋值为false,即锅里填满了材料了


使用单例模式之后

 

public class ChocolateFactory{
        private boolean empty;
        private boolean boiled;
 
        private static ChocolateFactorychocolateFactory = null;
 
        private ChocolateFactory(){
            empty = true;
            boiled = false;
        }
 
        public static ChocolateFactory getInstance(){
            if(chocolateFactory == null){
                chocolateFactory = newChocolateFactory();
            }else {
                return chocolateFactory;
            }
        }
 
 
        public void fill(){
            if(empty){
                empty = false;
                boiled = false;
            }
        }
 
        public void drain(){
            if((!empty)&&boiled){
                empty   = true;
            }
        }
 
 
        public void boid(){
            if((!empty)&&(!boiled)){
                boiled = true;
            }
        }
 
    }

 

然而,还没完呢


接下来是多线程的情况。线程是依据时间片来执行的。

看到下面这段代码

 public static ChocolateFactory getInstance(){
            if(chocolateFactory == null){
                chocolateFactory = newChocolateFactory();
            }else {
                return chocolateFactory;
            }
        }


如果现在两个线程,第一个线程thread1的时间片到了  if(chocolateFactory == null),这里先进行判断,然后执行chocolateFactory = newChocolateFactory();刚好在执行这段代码的时候,突然间时间片切换到第二个线程thread2,thread2也是执行这段代码,因为上一个时间片的时候,new创建对象还没有完成,指针还是为空。那么这个时候还是会new出一个对象。总的下来,两个线程就获取到了两个巧克力工厂对象,这是多线程不安全性的很好的体现


方法1:加上同步锁   Synchronized关键字


public static synchronized ChocolateFactorygetInstance(){
            if(chocolateFactory == null){
                chocolateFactory = newChocolateFactory();
            }else {
                return chocolateFactory;
            }
        }


这时,thread1执行创建对象时,如果时间片切换到thread2,因为线程thread1持有同步锁,线程2无法执行。这是要等到时间片再次切换到线程1, thread1执行完释放出同步锁后thread2才能继续执行。同步锁消耗资源比较多。


方法2:急切创建实例

public class ChocolateFactory{
	private boolean empty;
        private boolean boiled;
 
        private static ChocolateFactorychocolateFactory = new ChocolateFatory();
 
        private ChocolateFactory(){
            empty = true;
            boiled = false;
        }
}





看到private static ChocolateFactorychocolateFactory = new ChocolateFatory();

那么这个程序一开始运行就直接创建了这个对象,对象个数恒为1

 

方法3:双重检查加锁

public static ChocolateFactory getInstance(){
 
     if(chocolateFactory == null){
	synchronized(ChocolateFactory.class){
		if(chocolateFactory == null){
                      chocolateFactory = new ChocolateFactory();
                }
	}
     }
     return chocolateFactory;
}


这个方法也很好理解,就是同步锁住了一片区域,

synchronized(ChocolateFactory.class){
	if(chocolateFactory == null){
           chocolateFactory = new ChocolateFactory();
	}
}

较之简单粗暴的方法1,这种方法同步只会执行一次,消耗的资源比较少






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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值