从一个容器安全类引入单例模式

使用客户端加锁的Vector的复合操作

在我的上一盘博文中,

public class SafeContainer {
private Vector<Integer> vector;
private static SafeContainer safeContainer;

private SafeContainer() {
vector = new Vector<>();
}

public static SafeContainer getSafeContainer() {
if (safeContainer == null) {
safeContainer = new SafeContainer();
}
for (int i = 0; i < 50; i++) {
safeContainer.addLast(i);
}
return safeContainer;
}

public synchronized Integer deleteLast() {
int lastIndex = vector.size() - 1;
Integer remove = vector.remove(lastIndex);
return remove;
}

public synchronized void addLast(Integer integer) {
vector.add(integer);
}

public synchronized boolean isEmpty() {
return vector.isEmpty();
}

public synchronized Integer getLast() {
int size = vector.size() - 1;
Integer integer = vector.get(size);
return integer;
}

}

在这段代码中,我并不想把我的vector直接暴露给我外界,我只想允许其它类调用这个类二次封装的操作vector的方法来修改vector里面的属性。并且其它所有的类访问的都得是同一个vector里的内容。最简单的方式就是让这个类只能有一个对象。这个时候需要考虑的就是单例模式的设计。

单例模式的特点

  • 单例模式只能有一个实例。

  • 单例类必须创建自己的唯一实例。

  • 单例类必须向其他对象提供这一实例。

单例模式与静态类对比

静态类据我所知用的比较多的地方就是在建造者模式中,这篇文章中写的对比很详细。建议参考该文章。

单例模式的实现

  • 懒汉模式(Lazy loading)
    一开始的代码里使用的就是懒汉模式,在这个类创建的时候,并没有创建单例绑定到类的static域上,这个办法使用了非常明显的lazy load。所以叫懒汉模式,但是上面的代码不是线程安全的,所以需要处理同步。

  • 饿汉模式

    private Vector<Integer> vector;
    private static SafeContainer safeContainer = new SafeContainer();

    private SafeContainer() {
    vector = new Vector<>();
    }

    public static SafeContainer getSafeContainer() {
    for (int i = 0; i < 50; i++) {
    safeContainer.addLast(i);
    }
    return safeContainer;
    }

这里就相当于是直接把单例绑定到了safeContainer上了

  • 静态类内部加载
    private Vector<Integer> vector;

    private static class SingletonHelper {
    private static SafeContainerStaticLoad safeContainerStaticLoad= new SafeContainerStaticLoad();
    }

    public static SafeContainerStaticLoad getInstance() {
    return SingletonHelper.safeContainerStaticLoad;
    }

    private SafeContainerStaticLoad() {
    vector = new Vector<>();
    }

就是使用静态类内部的static字段来实现加载对象,使用内部类的好处是,静态内部类不会在单例加载时就加载,而是在调用getInstance()方法时才进行加载,达到了类似懒汉模式的效果,而这种方法又是线程安全的。

  • 枚举方法
    这个算是最好用,也是最简单的单例模式实现了
    SAFE_CONTAIN_ENUM();
    private Vector<Integer> vector;

    SafeContainEnum() {
    vector = new Vector<>();
    }

莫得了。它实现了

  • 自由序列化。

  • 保证只有一个实例。

  • 线程安全。

  • 双重校验锁法
    public class SingletonDemo {
    private static volatile SingletonDemo instance;
    private SingletonDemo(){
    System.out.println("Singleton has loaded");
    }
    public static SingletonDemo getInstance(){
    if(instance==null){
    synchronized (SingletonDemo.class){
    if(instance==null){
    instance=new SingletonDemo();
    }
    }
    }
    return instance;
    }
    }

丢一段代码吧,这个挺好理解的,这个其实就是两个线程调用getInstance方法的时候,由于对SingletonDemo.class加锁了,然后在一个线程获得实例的时候,另一个线程由于可见性,知道了instance对象不为空,所以就得到了第一个线程返回的对象的引用。


评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×