单例模式

GoF定义:保证一个类只有一个对象,并且提供一个全局的访问点

概念

一个特别的类只有一个实例,无论什么时候使用都是这同一个实例

例子

现实生活:假设有两个板球队伍在比赛,赛前两队的队长要投币决定哪方先击球,此时每个队的队长只能有一个,如果原来没有,那么要新选出一个队长
代码世界:代码只在一个文件系统上操作,那么这个文件系统的对象应该是全局唯一的

展示

  1. 将构造器声明为private
  2. 当创建这个类的实例时,如果已经存在,则使用这个实例,否则新建一个实例

public class SingletonPattern {

    public static void main(String[] args) {
        System.out.println("***Singleton Pattern Demo***\n");
        System.out.println("Trying to make a captain for our team");
        MakeACaptain c1 = MakeACaptain.getCaptain();
        System.out.println("Trying to make another captain for our team");
        MakeACaptain c2 = MakeACaptain.getCaptain();
        if (c1 == c2)
        {
            System.out.println("c1 and c2 are same instance");
        }
    }
}

class MakeACaptain {

    private static MakeACaptain makeACaptain;

    private MakeACaptain() {}

    public static MakeACaptain getCaptain() {
        if (makeACaptain == null) {
            makeACaptain = new MakeACaptain();
            System.out.println("New Captain selected for our team");
        } else {
            System.out.print("You already have a Captain for your team.");
            System.out.println("Send him for the toss.");
        }
        return makeACaptain;
    }
}

附加信息

上面代码的初始化模式为lazy initialization。因为直到静态方法被调用这个对象都不存在(可以在静态变量默认值直接新建一个对象)

上面代码的实例创建方式是线程不安全的,即(判断对象是否为空可能会让两个线程进入,那么会创建两个对象,那么它们持有的就不是同一个对象)

改进方式:

  1. 将返回实例的方法设为synchronized(同步操作会有额外开销(锁的开销))
public static synchronized MakeACaptain getCaptain()
  1. 提前把实例创建好
class MakeACaptain {

    private static MakeACaptain makeACaptain = new MakeACaptain();

    private MakeACaptain() {}

    public static synchronized MakeACaptain getCaptain() {
        return makeACaptain
    }
}
  1. 不使用同步,也不使用提前初始化,Java中标准的单例实现(这个方法的牛逼之处在于,类在加载时会有静态变量初始化的过程,这种方法利用了内部类的静态成员变量初始化需要加载内部类,实现了lazy initialization。对于final变量,只有当构造器调用完成,其它的线程才能看到,这个(Java语言的)机制保证了线程安全
class MakeACaptain
{
      private static MakeACaptain _captain;
      private MakeACaptain() { }
      //Bill Pugh solution
      private static class SingletonHelper{
            //Nested class is referenced after getCaptain() is called
            private static final MakeACaptain _captain = new MakeACaptain();
      }
      public static MakeACaptain getCaptain()
      {
            return SingletonHelper._captain;
      }
}
posted on 2020-11-24 18:15  老鼠不上树  阅读(101)  评论(0)    收藏  举报