一、什么是单例模式
单例模式是一种设计模式,它确保某个类只有一个实例,并提供一个全局访问点来获取该实例。这种模式在多种编程语言中都有实现,包括Java和C++。单例模式的实现可以采取饿汉式或懒汉式两种方式。饿汉式是在类加载时就创建了实例,而懒汉式则是在首次使用时才创建实例。懒汉式在多线程环境下可能会遇到线程安全问题,需要额外的线程安全措施来保证单例对象的唯一性。
在Java中,单例模式的实现可以通过私有构造函数、静态私有对象和静态公有函数来实现。
二、编写线程安全的懒加载单例模式
1、单例模式
//单例类:打印机
class Printer{
//提供静态的私有属性
private static Printer instance = null;
//私有的构造方法
private Printer(){
}
//向外部提供创建对象的静态方法
public static Printer getInstance(){
return new Printer();
}
}
2、懒加载
实现懒加载,就是在使用的时候才创建,修改提供对象方法:
//向外部提供创建对象的静态方法
public static Printer getInstance(){
//判断私有的静态对象是否为空
if(instabce == null){
//空则创建新对象
instance = new Printer();
}
return instance;
}
3、线程安全
多线程环境下上述代码存在问题,仍然可能导致对象被多次创建,所以需要加锁,避免多个线程同时创建对象,修改提供对象方法:
//向外部提供创建对象的静态方法
public static Printer getInstance(){
//判断私有的静态对象是否为空
if(instabce == null){
//加锁,避免对象被多个线程同时创建
synchronized(Printer.class){
//空则创建新对象
instance = new Printer();
}
}
return instance;
}
在创建对象的代码块上加上了synchronized阻塞锁,但多个线程同时进入 if 判断里面,对象仍会被多次创建,所以我们需要在加锁的代码块中再次判断,修改代码:
//向外部提供创建对象的静态方法
public static Printer getInstance(){
//判断私有的静态对象是否为空
if(instabce == null){
//加锁,避免对象被多个线程同时创建
synchronized(Printer.class){
//再次判断
if(instance != null){
return instance;
}
//空则创建新对象
instance = new Printer();
}
}
return instance;
}
三、单例模式的应用场景
单例模式的应用非常广泛,包括但不限于线程池、缓存、日志、对话框、打印机、显卡的驱动程序对象等。这些应用通常需要管理系统的全局资源,避免出现不一致的状态或浪费资源的情况。
此外,单例模式也有其缺点,例如没有接口导致扩展困难,以及在特定情况下可能会浪费内存资源(如饿汉式实现在类加载时就创建了实例)。因此,在设计单例模式时需要权衡其优缺点,根据具体的应用场景来选择合适的实现方式。