设计模式五之单例模式1

  单例模式,single instance,一个类只有一个对象、一个实例。怎么保证这个类生产的对象只有一个,如果在多线程的时候,如何保证线程安全。

  先给出一个没有保证线程安全的代码。

  

private static Single sin;
    private Single(){}
    
    // 不带线程安全的,因为sin是引用,在多线程中。当一个线程获取了引用,判断空否,
    // 这时候如果没有创建,那么就创建新对象。另一个线程这时候进来,这时候是正常进行的
    // 但是,考虑如果两个线程同时都在 == 判断,都判断为空,一个线程执行完了,返回了
    // 对象1,另一个对象这时候同样会new ,于是就出来第二个对象了。线程不安全。
    public static Single getInstance(){
        if (sin == null){
            sin = new Single();
        }
        return sin;
    }

  为上面说没有线程安全,通俗的说就是在开多线程的情况下,可能会出问题。下面给一个我随意写得一个代码。

  

ExecutorService exec = Executors.newFixedThreadPool(50);

        for (int i = 0; i < 100; i++) {
            exec.execute(new Runnable() {

                @Override
                public void run() {
                    Single s = Single.getInstance();
                    System.out.println(s.hashCode());
                    s.print();
                }
            });
        }

  执行情况, 这里只贴了一部分,这里的hash值有2个不对,说明不是一个对象。这个就有问题了。

41507015
41507015
Say Hello!
1088012372
Say Hello!
662611843
Say Hello!
41507015
Say Hello!
Say Hello!
41507015
Say Hello!
41507015
Say Hello!
41507015
Say Hello!
41507015
Say Hello!
41507015
Say Hello!
  

  单例模式,相比全局变量等,以上面的代码来看,在这里看又一个显著优点是延迟实例化。只是持有一个引用罢了。

  再贴一个最简单的线程安全的代码,这个理解来说也是挺好得,反正交给JVM来做。

private static Single sin = new Single();
    private Single(){}
    
    // 这里的方法是线程安全的,因为这是由JVM来保证的。sin作为类的引用,    JVM在加载这个类时就会
    // 有这个引用,并创建对象,要知道这可是类引用。不过带来的缺点是,创建时和运行时的负担比较繁重。
    public static Single getInstance(){
        return sin;
    }

  其实想一下,我们做Android开发的时候,经常需要用一些List的数据结构。

  有时候,我喜欢在类的头部,写

List<Goods> goodsList = new ArrayList<Goods>;
  在下面用的时候,直接add方法就好了,当然放在下面实例化也可以。
  再给出一种一般比较少用的方法,
  
private static volatile Single sin;

    private Single() {
    }

    // 这里也用了一个方法,用的是同步锁,不过这里面对其优化了一下,只是在第一次调用的时候需要同步一下
    // 后面就不需要了。同样可以保证线程安全。
    // volatile关键词,每次直接读值,不会因为编译器优化。相比全部的锁synchronized比起来效率
    // 要高一些。
    public static synchronized Single getInstance() {
        if (sin == null) {
            synchronized (Single.class) {
                if (sin == null) {
                    sin = new Single();
                }
            }
        }
        return sin;
    }

  上面是用了同步方法,另外加双重检查与锁。

public static volatile Single sin = null;
private Single(){}
public static Single getInstance() {
    if (null == sin){
        synchronized(Single.class){
            if(null == sin) {
                sin = new Single();
            }
        }
    }
    return sin;
}

以上也是一个办法

 

posted @ 2015-11-27 23:47  likeshu  阅读(149)  评论(0编辑  收藏  举报