Java23种设计模式之单例模式(Singleton)

131 阅读3分钟

概念:

单例模式在23种设计模式中属于创建型模式,是常见的设计模式之一。

案例:

这里以经典的数据库驱动连接工具类为例;

数据库连接工具类在各个业务的dao层会被初始化调用;

而每一次初始化都会在堆内存中申请一片空间,这是对堆内存资源的浪费;

如果在堆内存只开辟一片空间,各个业务的Dao层建立不同的引用进行操作,就可以资源利用最大化;                                                                                                                                     

单例设计模式就应运而生,它就是为了解决对象初始化,造成资源浪费的情况;

image.png

术语

单例:Singleton

image.png

三要素

  • 私有的构造方法;
  • 指向自己实例的私有静态引用;
  • 以自己实例为返回值的静态的公有方法。 分类         

1.饿汉式(静态常量)

/**
 *
 * @author 借我丹青妙笔
 * @create 2022-01-02 18:01 饿汉式(静态常量)
 */
public class DBAccess {
	// 构造器私有化,避免外部创建对象
	private DBAccess() {

	}

	// static修饰,保障其能够被静态方法访问
	private final static DBAccess dbAccess = new DBAccess();

	// 外部直接调用静态方法实例化对象
	public static DBAccess getInstance() {
		return dbAccess;
	}
}

2.饿汉式(静态代码块)

/**
 * 饿汉式(静态代码块)
 */
class DBAccess2 {
	private DBAccess2() {

	}

	private static DBAccess2 dbAccess = null;

	static {
		dbAccess = new DBAccess2();
	}

	public static DBAccess2 getInstance() {
		return dbAccess;
	}
}

3.懒汉式(线程不安全)

/**
 * 懒汉式(线程不安全)
 */
class DBAccess3 {
	private DBAccess3() {

	}

	private static DBAccess3 dbAccess = null;

	public static DBAccess3 getInstance() {
		if (dbAccess == null) {
			dbAccess = new DBAccess3();
		}
		return dbAccess;
	}
}

4.懒汉式(线程安全,同步代码块)

/**
 * 懒汉式(同步代码块)
 */
class DBAccess4 {
	private DBAccess4() {

	}

	private static DBAccess4 dbAccess = null;

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

5.懒汉式(线程安全,同步方法)

/**
 * 懒汉式(线程安全,同步方法)
 */
class DBAccess5 {
	private DBAccess5() {

	}

	private static DBAccess5 dbAccess = null;

	public synchronized static DBAccess5 getInstance() {
		if (dbAccess == null) {
			dbAccess = new DBAccess5();
		}
		return dbAccess;
	}
}

6.双重检查

/**
 * 双重检查
 */
class DBAccess6 {
	private DBAccess6() {

	}

	private static DBAccess6 dbAccess = null;

	public static DBAccess6 getInstance() {
		if (dbAccess == null) {
			synchronized (DBAccess6.class) {
				if (dbAccess == null) {
					dbAccess = new DBAccess6();
				}
			}
		}
		return dbAccess;
		// return new DBAccess6();
	}
}

7.静态内部类

/**
 * 静态内部类
 */
class DBAccess7 {
	private DBAccess7() {

	}

	private static class DBAccess7Instance {
		private static DBAccess7 dbAccess = new DBAccess7();
	}

	public static DBAccess7 getInstance() {
		return DBAccess7Instance.dbAccess;
	}
}

8.枚举

/**
 * 枚举
 */
enum DBAccess8 {
	DBACCESS;
	public static DBAccess8 getInstance() {
		return DBAccess8.DBACCESS;
	}
}

饿汉式和懒汉式的区别

(1)饿汉式和懒汉式的主要区别是他们使用的加载策略不同,饿汉式使用的是立即加载,而懒汉式用的是延迟加载(懒加载)。简单来说就是饿汉式不管你用不用,它都实例了。而懒汉式是当你调用方法时它才去实例。

(2)饿汉式虽存在性能问题,但它是线程安全的,而懒汉式可能存在线程不安全的问题,当然也可以通过同步代码块或同步方法的方式解决,如上面4、5。(注:4比5的性能更好)。

结论:

单例中两种饿汉式可用,但是存在性能问题 单例中三种懒汉式不推荐,存在线程安全问题,同步方法的方式解决了线程的问题,但是性能极差 最后三种单例模式值得推荐

注意事项

系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能

当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用 new

应用

  • jdk源码中Runtime类
  • tomcat中ApplicationContext类
  • session 工厂

通过以上讲解,为大家详细介绍了Java23种设计模式里比较常见的单例模式。想要系统学习更多编程基础知识的同学可以戳视频链接继续~