在我们开发的 Android 项目中,单例模式可能是我们用的最多的开发模式了,但是对于这种常用的开发模式,我们真的用对了吗?本篇博文我们就来探讨一下单例模式。
前言
在讨论之前,我们先来看一下新手使用单例模式,最常见的代码,如下:
1 | public class Singleton { |
上面的单例代码咋一看上去没什么问题,其实问题很大,真的很大。这并不是真的单例。
什么是单例?
简单来说,就是在程序的运行过程中,只保持一个实例对象。
为什么要用单例?
在我们开发项目的过程中,某些类存在占用资源较大,每次 new 的时候性能消耗较大,这个时候我们应考虑使用单例来提高性能。
使用单例要注意什么?
主要有以下三点:
- 1.私有化构造器;
- 2.定义静态的单例
instance对象 和getInstance()方法; - 3.
getInstance()方法中要使用同步锁synchronized(Singleton.class)防止多线程多次示例化。
实践
在我们写正确的 单例 代码前,我们先来测试以下博文开头给出的这种单例 demo 为何不对;
错误点有以下几方面:
- 1.未私有化构造器,这样就导致了调用者可能越过
getInstance()方法,直接调用默认的公有的构造器来new对象。 - 2.
getInstance()方法未加锁,多线程调用时,可能多次示例化对象。
所谓口说无凭,我们看下面的测试代码,来实际验证以下是否真的存在多次实例化对象:
1 | final CountDownLatch latch = new CountDownLatch(1); |
查看 Log:

我们明显和可以看到示例对象的 hashCode 有两个不同的值,也就是说对象在多线程的情况下,被实例化了两次。
接下来是正确的单例代码 demo:
1 | public class Singleton { |
需要注意的是:
- 1.在
getInstance()方法中有两次判空,第一次判空是为了防止sInstance已经实例化后,再次获取锁对象。这样做可以提高性能。 - 2.很多人都会重新
new Object()来充当synchronized锁对象,完全没有必要新建一个对象,我们直接用单列对象本身即可,防止消耗不必要的内存。