创建型模式之单例设计模式

红烧土豆泥 等级 309 0 0

什么是单例设计模式? 顾名思义,只有一个实例。 单例模式它主要是确保一个类只有一个实例,并且可以提供一个全局的访问点。 废话少说,直接上干货了~

单例模式之饿汉式 所谓饿汉式,顾名思义,“ 它很饿 ”。所以说,它一旦被加载进来,就会直接实例化一个对象。 例如:

  class Singleton {
    private static final Singleton SINGLE = new Singleton();

    private Singleton() {
    }

    public static Singleton getInstance() {
        return SINGLE;
    }

    public void print() {
        System.out.println("hello,我是饿汉~ 哇咔咔~");
    }
}

接下来编写一个测试类

  @Test
    public void TestSingleton() {
        Singleton s = Singleton.getInstance();
        s.print();
    }

运行效果: 创建型模式之单例设计模式

结果异常顺利,就这样结束了吗?肯定不会就这样简单啦!我们再来看一下它在多线程的情况下运行效果如何?

  class Singleton {
    private static final Singleton SINGLE = new Singleton();

    private Singleton() {
        System.out.println("我出来啦~");
    }

    public static Singleton getInstance() {
        return SINGLE;
    }

    public void print() {
        System.out.println("hello,我是饿汉~ 哇咔咔~");
    }
}

测试类:

  @Test
    public void TestSingleton() {
        for (int i = 0; i < 3; i++) {
            new Thread(()->{
                Singleton s = Singleton.getInstance();
                s.print();
            }).start();
        }
    }

结果: 创建型模式之单例设计模式 可以看到,测试结果还是异常丝滑。

那让我们再来看看它兄弟 --> 单例模式之懒汉式 一听他名字,就知道它比较懒,肯定一上来就不会进行实例化,而是先判断,先问一下你有对象了吗?如果没有的话,再给你分配。 所以说,它的写法应该是:

  class Singletonss{
    private static Singletonss SING = null;

    private Singletonss() {
        System.out.println("我是懒汉,我出来啦~");
    }

    public static Singletonss getInstance() {
        if(SING == null) {
            SING = new Singletonss();
        }
        return SING;
    }

    public void print() {
        System.out.println("hello,我是懒汉~ 哇咔咔~");
    }

}

下面是一个测试类:

  @Test
    public void TestSingleton() {
        Singletonss s = Singletonss.getInstance();
        s.print();
    }

看一下运行结果: 创建型模式之单例设计模式 貌似是一切正常,风平浪静,没什么太大问题~ 然后,让我们再来偷偷瞅一下它在多线程的情况下是什么妖怪吧~ 还是用上面的懒汉式代码,然后编写一个测试

  @Test
    public void TestSingleton() {
        for(int i=0;i<3;i++) {
            new Thread(()->{
                Singletonss s = Singletonss.getInstance();
                s.print();
            }).start();
        }
    }

创建型模式之单例设计模式 是不是被突然跳出来的饿汉吓到了,我才开启了三个线程,他竟然出来了三次~ 让我们分析一下是什么原因吧!可能细心的小伙伴们已经想到,多线程情况下,每个线程都会竞相抢夺资源,所以说第一个线程它在执行if判断但还未进行new的时候,别的线程也可能进入了if判断,所以说就会出现饿汉单例被实例化多次的情况,如何解决勒,有的人可能回想直接给那个方法加synchronized关键字,每次只允许一个线程进入。没错,这样是可以解决掉这问题,但是,如果给方法加了同步,也就意味着,线程资源来到这之后,只能先进入一个,别的需要排队等待这,如果只有一两个线程还好,如果说有几千个线程在这,无疑这样会大大浪费了资源,拖慢了程序的进度,所以这种方法不是最优的。那如果是给if判断加同步嘞?

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

感觉上还是蛮好的,但是与上个方法没太大区别。那,这,,,咋整哇~ 其实我们可以让每个先到的线程先进入if判断,然后开启同步,然后再进行一次判断,让先来的去实例化,后来的一看已经被实例化好了,就可以直接返回了。这样可以很大程度上减少线程等待时间。具体实现代码如下:

  class Singletons {

    private static volatile Singletons single = null;

    private Singletons() {
        System.out.println("我是懒汉,我出来啦~");
    }

    public static Singletons getInstance() {
        if (single == null) {
            synchronized (Singleton.class) {
                if (single == null) {
                    single = new Singletons();
                }
            }
        }
        return single;
    }

    public void print() {
        System.out.println("hello,我是懒汉~ 哇咔咔~");
    }
}

测试类:

  @Test
    public void TestSingleton() {
        for(int i=0;i<3;i++) {
            new Thread(()->{
                Singletons s = Singletons.getInstance();
                s.print();
            }).start();
        }
    }

再来看一下与运行结果: 创建型模式之单例设计模式 一切正常

收藏
评论区