单例模式

单例模式

定义

保证一个类仅有一个实例,并且提供一个访问它的全局访问点。

UML

对象说明

Singleton:定义一个getInstance()操作,允许客户访问它的唯一实例。getInstance()是一个静态方法,主要负责创建自己的唯一实例。

Demo

public class SingletonTest {
    public static void main(String[] args) {
        //超人对象应该是唯一的。保证superMan的唯一性。可使用单例模式解决。
        Superman superman=Superman.getInstance();
        superman.func();
        superman.setName("iron man");
        superman.func();
    }
}
​
class Superman{
    /**
     * 确定英雄的名字
     * */
    private String name;
​
    public String getName() {
        return name;
    }
​
    public void setName(String name) {
        this.name = name;
    }
​
    /**
     * 自己创建一个实例,供外界调用,保证对象的唯一性
     * */
    private static Superman superman=new Superman("Hero");
​
    /**
     * 私有化构造函数
     * @param name :超人的姓名
     * */
    private Superman(String name) {
        this.name = name;
    }
​
    /**
     * 返回用户所希望调用的实例
     * */
    public static Superman getInstance(){
        return superman;
    }
​
    /**
     * 确定蜘蛛侠的能够实现的方法
     * */
    public void func(){
        System.out.println(this.name+"  fly...");
    }
}

单例模式实现步骤分析

1,一个类只要提供了构造函数,就可以产生多个对象。完全无法保证唯一。那么也就无法保证对象的唯一性。既然对象数量不可控,干脆,不让其他程序建立对象。

2,不让其他程序创建,对象何在? ​ 自己在本类中创建一个对象,这样好处是什么,可控。

3,创建完成后,是要给其他程序提供访问的方式。就是访问这个对象的方式。

单例模式实现的两种形式

//饿汉式
class Single
{
    //2,创建一个本类对象。
    private static /*final*/ Single s = new Single();
​
    //1,私有化构造函数。
    private Single(){}
​
    //3,定义一个方法返回这个对象。
    public static Single getInstance()
    {
        return s;
    }
}
//懒汉式
//单例的延迟加载方式。面试最多的是懒汉式。
class Single2
{
    private static Single2 s2 = null;
​
    private Single2(){}
​
    public static Single2 getInstance()
    {
        if(s2==null)
            s2 = new Single2();
        return s2;
    }
}

单例模式在多线程里面的操作

在多线程的程序中,多个线程同时访问Singleton,调用getInstance()方法的时候,会有可能创建多个实例。那么在实际的操作过程中,我们可以给进程来加一把锁lock来确定。lock是确保当一个线程位于代码的临界区时,另一个线程不进入临界区。如果有其他的线程试图进入锁定的代码,则它将一直等待,直到该对象被释放。

基于synchronize的实现

public class Singleton1 {
    private static Singleton1 instance=null;
​
    private Singleton1() {
    }
​
    public static Singleton1 getInstance(){
        if (instance==null){
            //采用synchronized关键字来保证同步
            synchronized (Singleton1.class){
                if (instance==null){
                    instance=new Singleton1();
                }
            }
        }
    return instance;
    }
}

采用双重锁定的原因:当instance存在时,直接返回,不创建实例,这没有问题,当instancenull的时候,并且存在两个线程同时调用getInstance()方法的时候,它们都可以通过第一层的判断,然后由于锁机制,只有一个线程可以进入创建实例,创建完成后释放锁,但是第二个线程仍然可以去创建实例,这就没有达到我们单例模式的要求,所以需要双重锁定。

学习Lock

class BoundedBuffer {
   final Lock lock = new ReentrantLock();//锁
   final Condition notFull  = lock.newCondition(); //生产
   final Condition notEmpty = lock.newCondition(); //消费
​
   final Object[] items = new Object[100];//存储商品的容器。
   int putptr/*生产者使用的角标*/, takeptr/*消费者使用的角标*/, count/*计数器*/;
​
    /*生产者使用的方法,往数组中存储商品*/
   public void put(Object x) throws InterruptedException {
     lock.lock();
     try {
       while (count == items.length) //判断计数器是否已到数组长度。满了。
         notFull.await();//生产就等待。
​
       items[putptr] = x; //按照角标将商品存储到数组中
​
       if (++putptr == items.length) //如果存储的角标到了数组的长度,就将角标归零。
            putptr = 0;
       ++count;//计数器自增。
       notEmpty.signal();//唤醒一个消费者
     } finally {
       lock.unlock();
     }
   }
​
   public Object take() throws InterruptedException {
     lock.lock();
     try {
       while (count == 0) //如果计数器为0,说明没有商品,消费者等待。
         notEmpty.await();
       Object x = items[takeptr]; //从数组中通过消费者角标获取商品。
​
       if (++takeptr == items.length) //如果消费的角标等于了数组的长度,将角标归零。
           takeptr = 0;
       --count;//计数器自减。
       notFull.signal();//唤醒生产者。
       return x;
     } finally {
       lock.unlock();
     }
   } 
 }

小结

单例设计模式保证了一个类的对象的唯一性。比如多个程序都要使用一个配置文件中的数据,而且要实现数据共享和交换。必须要将多个数据封装到一个对象中。而且多个程序操作的是同一个对象。那也就是说必须保证这个配置文件对象的唯一性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值