单例模式: 保证一个类只有一个实例, 并提供一个全局访问点。(可以说是最简单的模式, 从零单排冲天梯)
类图:
抽象实现:
1. 懒汉模式 (懒得判断是否已经实例化, 先进行实例化)
- package com.wenniuwuren.singleton;
-
- public class Singleton {
-
-
-
-
-
- private static Singleton uniqueInstance = new Singleton();
-
-
-
-
- private Singleton() {
-
- }
-
-
-
-
- public static Singleton getInstance() {
- return uniqueInstance;
- }
-
-
-
- }
适用于对程序性能有较大要求的地方, 如果用饱汉模式(详情见下文)要对线程加同步锁降低系统性能。
2. 饱汉模式(采用了volatile和同步块来保证并发安全性, 不像上面的懒汉模式直接就实例化了, 因为饱汉模式存在着判断和赋值,所以必须加上安全机制保障并发的正确性。 例如:线程A判断uniqueInstance为null进入方法, 然后new了实例, 但是还没赋值给uniqueInstance, 这时CPU把时间给了线程B, 此时的uniqueInstance还未赋值所以又new了一次实例, 那么这就破坏了单例模式了)
- package com.wenniuwuren.singleton;
-
- public class Singleton {
-
-
-
-
-
-
-
- private volatile static Singleton uniqueInstance = null;
-
-
-
-
- private Singleton() {
-
- }
-
-
-
-
- public static Singleton getInstance() {
- if (uniqueInstance == null) {
-
- synchronized (Singleton.class) {
- if (uniqueInstance == null) {
- return uniqueInstance = new Singleton();
- }
- }
- }
- return uniqueInstance;
- }
-
- }
当然如果系统对性能要求不高, 饱汉模式可以不像上面那么复杂, 直接在getInstance()方法上加同步修饰字段synchronized即可。
但是上面的方法虽然已经把同步代码块缩减到最小, 但是还是对性能有一点影响, 接下来介绍另一种保障线程安全的方法并且不使用同步代码块和volatile字段修饰。
- public class Singleton {
-
- private Singleton(){}
-
-
-
- private static class SingletonHolder{
- private static Singleton instance = new Singleton();
- }
-
- public static Singleton getInstance(){
- return SingletonHolder.instance;
- }
- }
应用场景:
- 网站的计数器, 不然并发计数访客什么的数量肯定会乱
- 应用程序的日志, 并发写日志不控制安全性日志重复写入多次
- Spring中的Bean默认也是单例的
参考书籍:
《设计模式:可复用面向对象软件的基础》
《Java并发编程实战》