这个模式一年前学完的,今天看看博客竟然没有总结!!!单例模式应该是最早接触的模式了吧!
单例模式分为饿汉式和懒汉式
1. 饿汉式(静态常量)
优点:使用静态常量,因此在类加载的时候创建了,所以是线程安全的。
缺点:因为在类加载的时候就创建了,所以如果程序中从来没有使用过该类的实例,那么就会出现内存浪费。
2. 饿汉式(静态块)
优点:使用静态常量,因此在类加载的时候创建了,所以是线程安全的。
缺点:因为在类加载的时候就创建了,所以如果程序中从来没有使用过该类的实例,那么就会出现内存浪费。
3. 懒汉式(线程不安全)
懒汉式:在需要的时候再创建,而不是之前在类加载的时候就在JVM中加载好了。
- 优点:不会造成内存浪费
- 缺点:线程不安全-》假设现在两个线程同时执行到了【第13行】,这两个线程同时认为该类中没有INSTANCE实例,就会同时创建INSTANCE实例,导致线程不安全。
4. 懒汉式(线程安全,效率低)
我们可以看到在【第12行】加了synchronized关键字,我们知道虽然synchronized关键字在JDK1.8中有优化,但是给这一整个方法加锁怎么样说这个锁都太粗了吧。。。
5. 懒汉式(线程不安全,同步代码块)
为了解决第四种情况的效率低的问题,我们将 synchronized 关键字改在了方法体里面,这次是给类加同步,但是这样会导致线程不安全。为什么呢?
我们还假设 现在有两个线程(A和B)同时到达了【第13行】,这两个线程都得到了 INSTANCE == null。所以又同时到达了【第14行】,假设线程A很幸运抢过了线程B,它得到了锁,那么它吭哧吭哧执行,知道执行到【第16行】之后,将锁释放了,这个时候线程B获取到了锁,那么它会从它卡住的位置继续执行下去,好了!他从哪里卡主的呢?是从【第14行】吧,所以,他继续执行到【第15行】,糟了,又创建了INSTANCE实例。所以就又变成线程不安全的了。
6. 懒汉式(双重检查)
OK ,这回在 进入同步块之后,又来了一个是否为空的检查,这次就不会出现情况五的问题了,完美解决。效率又高,线程又安全。
7. 静态内部类
这种方式跟饿汉式方式采用的机制类似,但又有不同。两者都是采用了类装载的机制来保证初始化实例时只有一个线程。不同的地方在饿汉式方式是只要Singleton类被装载就会实例化,没有Lazy-Loading的作用,而静态内部类方式在Singleton类被装载时并不会立即实例化,而是在需要实例化时,调用getInstance方法,才会装载SingletonInstance类,从而完成Singleton的实例化。