什么是单例设计模式? 顾名思义,只有一个实例。 单例模式它主要是确保一个类只有一个实例,并且可以提供一个全局的访问点。 废话少说,直接上干货了~
单例模式之饿汉式 所谓饿汉式,顾名思义,“ 它很饿 ”。所以说,它一旦被加载进来,就会直接实例化一个对象。 例如:
1 class Singleton { 2 private static final Singleton SINGLE = new Singleton(); 3 4 private Singleton() { 5 } 6 7 public static Singleton getInstance() { 8 return SINGLE; 9 } 10 11 public void print() { 12 System.out.println("hello,我是饿汉~ 哇咔咔~"); 13 } 14}
接下来编写一个测试类
1 @Test 2 public void TestSingleton() { 3 Singleton s = Singleton.getInstance(); 4 s.print(); 5 }
运行效果:

结果异常顺利,就这样结束了吗?肯定不会就这样简单啦!我们再来看一下它在多线程的情况下运行效果如何?
1 class Singleton { 2 private static final Singleton SINGLE = new Singleton(); 3 4 private Singleton() { 5 System.out.println("我出来啦~"); 6 } 7 8 public static Singleton getInstance() { 9 return SINGLE; 10 } 11 12 public void print() { 13 System.out.println("hello,我是饿汉~ 哇咔咔~"); 14 } 15}
测试类:
1 @Test 2 public void TestSingleton() { 3 for (int i = 0; i < 3; i++) { 4 new Thread(()->{ 5 Singleton s = Singleton.getInstance(); 6 s.print(); 7 }).start(); 8 } 9 }
结果:
可以看到,测试结果还是异常丝滑。
那让我们再来看看它兄弟 --> 单例模式之懒汉式 一听他名字,就知道它比较懒,肯定一上来就不会进行实例化,而是先判断,先问一下你有对象了吗?如果没有的话,再给你分配。 所以说,它的写法应该是:
1 class Singletonss{ 2 private static Singletonss SING = null; 3 4 private Singletonss() { 5 System.out.println("我是懒汉,我出来啦~"); 6 } 7 8 public static Singletonss getInstance() { 9 if(SING == null) { 10 SING = new Singletonss(); 11 } 12 return SING; 13 } 14 15 public void print() { 16 System.out.println("hello,我是懒汉~ 哇咔咔~"); 17 } 18 19}
下面是一个测试类:
1 @Test 2 public void TestSingleton() { 3 Singletonss s = Singletonss.getInstance(); 4 s.print(); 5 }
看一下运行结果:
貌似是一切正常,风平浪静,没什么太大问题~
然后,让我们再来偷偷瞅一下它在多线程的情况下是什么妖怪吧~
还是用上面的懒汉式代码,然后编写一个测试
1 @Test 2 public void TestSingleton() { 3 for(int i=0;i<3;i++) { 4 new Thread(()->{ 5 Singletonss s = Singletonss.getInstance(); 6 s.print(); 7 }).start(); 8 } 9 }
是不是被突然跳出来的饿汉吓到了,我才开启了三个线程,他竟然出来了三次~
让我们分析一下是什么原因吧!可能细心的小伙伴们已经想到,多线程情况下,每个线程都会竞相抢夺资源,所以说第一个线程它在执行if判断但还未进行new的时候,别的线程也可能进入了if判断,所以说就会出现饿汉单例被实例化多次的情况,如何解决勒,有的人可能回想直接给那个方法加synchronized关键字,每次只允许一个线程进入。没错,这样是可以解决掉这问题,但是,如果给方法加了同步,也就意味着,线程资源来到这之后,只能先进入一个,别的需要排队等待这,如果只有一两个线程还好,如果说有几千个线程在这,无疑这样会大大浪费了资源,拖慢了程序的进度,所以这种方法不是最优的。那如果是给if判断加同步嘞?
1 public static Singletonss getInstance() { 2 synchronized (Singletonss.class) { 3 if(SING == null) { 4 SING = new Singletonss(); 5 } 6 } 7 return SING; 8 }
感觉上还是蛮好的,但是与上个方法没太大区别。那,这,,,咋整哇~ 其实我们可以让每个先到的线程先进入if判断,然后开启同步,然后再进行一次判断,让先来的去实例化,后来的一看已经被实例化好了,就可以直接返回了。这样可以很大程度上减少线程等待时间。具体实现代码如下:
1 class Singletons { 2 3 private static volatile Singletons single = null; 4 5 private Singletons() { 6 System.out.println("我是懒汉,我出来啦~"); 7 } 8 9 public static Singletons getInstance() { 10 if (single == null) { 11 synchronized (Singleton.class) { 12 if (single == null) { 13 single = new Singletons(); 14 } 15 } 16 } 17 return single; 18 } 19 20 public void print() { 21 System.out.println("hello,我是懒汉~ 哇咔咔~"); 22 } 23}
测试类:
1 @Test 2 public void TestSingleton() { 3 for(int i=0;i<3;i++) { 4 new Thread(()->{ 5 Singletons s = Singletons.getInstance(); 6 s.print(); 7 }).start(); 8 } 9 }
再来看一下与运行结果:
一切正常
