1.单例模式

本文深入解析单例模式的定义、特点及其六种实现方式:懒汉模式、饿汉模式、双检锁模式、内部类模式、枚举实现。对比各模式的优缺点,如线程安全性、资源消耗等,推荐使用内部类模式。

单例模式

1.定义

  • 所谓单例,就是整个程序有且仅有一个实例。该类负责创建自己的对象,同时要确保只有一个对象被创建。

  • 好处:就是一个类你只能创建一个实例对象可以节约内存开销,一般常用于在工具类的实现(之前的静态方法也可以用于工具类的实现)。

2.特点

  1. 构造器私有
  2. 持有自己类的属性
  3. 对外提供获取实例的静态方法

一般单例模式分为两大类:懒汉模式,饿汉模式.详细分其实有懒汉,饿汉,双检锁,内部类,枚举。

3.懒汉模式

/**
 * 	懒汉模式,延迟初始化,在调用方法获取的时候才会实例对象
 * 	线程不安全的,严格意义上不是单例模式
 * @author Administrator
 *
 */
public class Singleton {
	//持有自己类型的属性
	private static Singleton instance;
	
	//构造方法私有化
	private Singleton() {}
    
	//对外提供获取实例的静态方法
	public static Singleton getInstance() {
		if(instance==null) {
			instance=new Singleton();
		}
		return instance;
	}	
}

测试

public class Test {
	public static void main(String[] args) {
		Singleton instance1 = Singleton.getInstance();
		Singleton instance2 = Singleton.getInstance();
		System.out.println(instance1==instance2);
	}
}

结果

true

4.饿汉模式

线程安全,比较常用,但是容易产生垃圾,因为饿汉模式一开始加载类的时候就初始化了实例。

/**
 * 	饿汉模式
 * @author Administrator
 *
 */
public class Singleton {
	//持有自己类型的属性
	//由于static修饰,只在加载类的时候执行一次
	private static Singleton instance = new Singleton();
	
	//构造方法私有化
	private Singleton() {}

	//对外提供获取实例的静态方法
	public static Singleton getInstance() {
		return instance;
	}
}

测试

public class Test {
	public static void main(String[] args) {
		Singleton instance1 = Singleton.getInstance();
		Singleton instance2 = Singleton.getInstance();
		System.out.println(instance1==instance2);
	}
}

结果

true

懒汉模式和饿汉模式的区别

  1. 懒汉是非线程安全,饿汉是线程安全
  2. 懒汉模式是一开始不实例化对象,调用方法时才实例化对象,饿汉模式一开始实例化对象,容易造成资源浪费.

综合两者的优缺点,可以使用双检锁模式。

5.双检锁模式

双检锁也称双重校验锁,综合了懒汉模式和饿汉模式的优缺点

/**
 * 	双检锁模式结合懒汉模式和饿汉模式的优点:延迟加载并且线程安全
 * @author Administrator
 *
 */
public class Singleton {
	
	//持有自己类型的属性
	private volatile static Singleton instance;
	
	//构造方法私有化
	private Singleton() {}
	
	//对外提供获取实例的静态方法
	public static Singleton getInstance() {
		if(instance==null) {
			synchronized(Singleton.class) {
				if(instance==null) {
					instance=new Singleton();
				}
			}	
		}
		return instance;
	}
}

小结:

  • 双检锁模式,进行两次判断,第一次判断是为了避免不要的实例,第二次是为了进行线程同步,避免多线程问题,由于newsingleton()创建instance对象的时候jvm中可能会重新排序,在多线程存在风险,使用volatile关键字可以当线程改变其值后通知其他线程已改变并且不会被java重新排序,解决该问题

6.内部类模式

/**
 * 	内部类模式实现单例模式
 * @author Administrator
 *
 */
public class Singleton {
	private Singleton() {}
	
	public static Singleton gatInstance() {
		return Inner.instance;
	}
	
	public static class Inner{
		//final修饰的常量,不能再被改变
		private static final Singleton instance= new Singleton();
	}
}

小结

  • 只有第一次调用gatInstance()方法时,虚拟机才加载Inner内部类并初始化instance,只有一个线程可以获取instance对象的初始化,其他线程无法再进行初始化,线程安全的,保证对象的唯一性。【推荐使用此方式实现单例模式】

7.枚举实现

/**
 * 	默认枚举的实例是线程安全的,并且在任何情下都是单例
 * 	枚举类默认隐藏了所有的构造方法
 * 
 * @author Administrator
 *
 */
public enum Singleton {
	INSTANCE;
	
	public static Singleton getInstance() {
		return Singleton.INSTANCE;
	}
}
单例设计模式是一种常见的创建型设计模式,其主要目标是确保一个类只有一个实例,并提供一个全局访问点[^1]。根据多个引用提供的实现方式和定义,可以分析以下可能的错误描述: ### 常见错误描述示例(假设选项如下): 1. **单例模式可以通过将构造函数设为公有来实现** - 此描述是错误的。单例模式的核心在于限制外部直接通过构造函数创建对象,因此构造函数必须设置为私有(private),以防止其他代码随意实例化该类[^4]。 2. **单例类允许外部通过 `new` 操作符创建多个实例** - 此描述是错误的。单例模式的设计初衷就是避免多次实例化,从而保证系统资源的合理利用。如果允许通过 `new` 创建多个实例,则违背了单例的基本原则[^3]。 3. **饿汉式单例在类加载时不会立即创建实例** - 此描述是错误的。饿汉式(Eager Initialization)的特点就是在类加载阶段就立即创建实例,而不是等到第一次使用时才创建[^4]。 4. **懒汉式单例在多线程环境下无需考虑线程安全问题** - 此描述是错误的。懒汉式(Lazy Initialization)在多线程环境下如果不加同步机制,可能会导致创建多个实例的问题。因此通常需要使用同步锁或双重检查锁定(DCL)机制来保证线程安全[^5]。 5. **单例模式适用于只需要一个实例的场景,如任务管理器、数据库连接池等** - 此描述是正确的。单例模式非常适合用于管理共享资源,例如数据库连接、线程池、日志对象等,这些对象只需一个实例即可服务整个系统[^2]。 --- ### 示例代码:线程安全的懒汉式单例 ```java public class Singleton { private static volatile Singleton instance; private Singleton() {} public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } } ``` 上述代码使用了双重检查锁定(DCL)机制,确保在多线程环境下也能正确地只创建一个实例[^5]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值