【单例模式】饿汉式,懒汉式?JAVA如何实现单例?线程安全吗?

2023-10-25 14:41:35 浏览数 (2)

个人简介:Java领域新星创作者;阿里云技术博主、星级博主、专家博主;正在Java学习的路上摸爬滚打,记录学习的过程~ 个人主页:.29.的博客

Java单例设计模式

  • 单例设计模式(Singleton):单例即唯一实例,某个类在整个系统中只能有一个实例对象可被获取和使用的代码模式。(例如:代表JVM运行环境的Runtime类)

要点

  • ①某个类只能有一个实例。
    • 构造器私有化。
  • ②这个类必须自行创建这个实例。
    • 含有一个该类的静态变量来保存这个唯一的实例。
  • ③这个类必须自行向整个系统提供这个实例。
    • 对外提供获取该实例的方式:
        1. 直接暴露
        2. 用静态变量的get方法获取

饿汉式

  • 饿汉式:直接创建对象,不存在线程安全问题。(在类初始化时直接创建对象,不管你是否需要这个对象都会创建)
  • 实现方式:
    • 直接实例化饿汉式(简洁明了)
    • 枚举式(最简洁)
    • 静态代码块饿汉式(适合复杂实例化)
  1. 直接实例化
代码语言:javascript复制
//Singleton:单例设计模式,软件开发中常见的设计模式之一

//单例设计模式——饿汉式1:直接实例化饿汉式
/*
 * 1.构造器私有化
 * 2.自行创建,并且用静态变量保存
 * 3.向外提供这个实例
 * 4.使用final修饰,强调这是一个单例
 */
public class Singleton_hungry1 {
	//直接实例化
	private static final Singleton_hungry1 INSTANCE = new Singleton_hungry1();
	
	//构造器私有化
	private Singleton_hungry1(){}
	
}
  1. 枚举式
代码语言:javascript复制
/**
 * 枚举类型:表示该类型的变量是有限的几个
 * 我们可以限定为一个,从而成了单例
 *
 */
public enum Singleton_hungry2 {
	//枚举类型的实例
	INSTANCE;
	private Singleton_hungry2() {}
}
  1. 静态代码块
代码语言:javascript复制
public class Singleton_hungry3 {
	public static final Singleton_hungry3 INSTANCE;
	
	static {
		//复杂情况在静态代码块中解决
		INSTANCE = new Singleton_hungry3();
	}
	
	private Singleton_hungry3() {}
}

懒汉式

  • 懒汉式:延迟创建对象。
  • 实现方式:
  • 线程不安全(适用于单线程)
  • 线程安全(适用于多线程)
  • 静态内部类形式(适用于多线程)
  1. 线程不安全
代码语言:javascript复制
/*
 * 懒汉式:延迟创建这个实例对象
 * 1. 构造器私有化
 * 2.用一个静态变量保存唯一实例
 * 3.提供一个静态方法,用于获取实例*/
public class Singleton4 {
	private static Singleton4 instance;
	
	private Singleton4() {}
	
	//线程不安全
	public static Singleton4 getInstance() {
		if(instance == null) {
			instance = new Singleton4();
		}
		return instance;
	}
	
}
  1. 线程安全
代码语言:javascript复制
public class Singleton5 {
	private static Singleton5 instance;
	
	private Singleton5() {}
	
	public static Singleton5 getInstance() {
		//上锁、线程安全
		synchronized(Singleton5.class){
			if(instance == null) {
				instance = new Singleton5();
			}
		}
		
		return instance;
	}
	
}
  1. 静态内部类形式
代码语言:javascript复制
/*
 * 懒汉式:延迟创建这个实例对象
 * 1. 构造器私有化
 * 2.用一个静态变量保存唯一实例
 * 3.提供一个静态方法,用于获取实例*/
public class Singleton6 {
	
	private Singleton6() {}
	
	//内部类:静态内部类不会随着外部类的加载和初始化而初始化,它是要单独去加载和初始化的
	//唯一实例因为是在内部类加载和初始化时才创建的,所以线程安全
	private static class inner{
		//唯一实例: 在内部类被加载和初始化时才被创建
		private static Singleton6 instance = new Singleton6();
	}
	
	public static Singleton6 getInstance() {
		return inner.instance;
	}
	
}

0 人点赞