设计模式——单例模式

文章介绍了Java中的单例模式,包括懒汉式和饿汉式的实现方式。懒汉式在类加载时创建单例,而饿汉式在调用时创建,后者在多线程环境下可能引发问题。为解决线程安全,可以使用同步锁,但会影响效率。文章提出了一种改进的懒汉式实现,通过双重检查锁定和volatile关键字确保线程安全且提高效率。此外,文章还以Runtime类为例说明了单例模式在实际应用中的体现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

单例模式分为懒汉式和饿汉式两种

       在有些系统中,为了节省内存资源、保证数据内容的一致性,对某些类要求只能创建一个实例,这就是所谓的单例模式. 例如,Windows 中只能打开一个 任务管理器,这样可以避免因打开多个任务管理器窗口而造成内存资源的浪费, 或出现各个窗口显示内容的不一致等错误。

单例模式有 3 个特点:

1. 单例类只有一个实例对象;
2. 该单例对象必须由单例类自行创建;
3. 单例类对外提供一个访问该单例的全局访问点;

懒汉式单例模式:

在类加载时便进行单例对象的创建,不会因为线程产生不安全原因

public class Wonder {
    public static Wonder wonder=new Wonder();

    private Wonder(){}

    public static Wonder getWonder(){
        return wonder;
    }
}

饿汉式单例模式:

在使用访问方法时才进行单例对象进行生成操作,在多线程的情况下有问题


public class Wonder {
    public static Wonder wonder;

    private Wonder(){}

    public static Wonder getWonder(){
      if(wonder==null){
          try {
              Thread.sleep(1000);
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
          wonder=new Wonder();
      }
      return wonder;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(()->{
                System.out.println(Wonder.getWonder());
            }).start();
        }
    }
}

所以需要处理线程安全问题,可以给访问方法添加锁


public class Wonder {
    public static Wonder wonder;

    private Wonder(){}

    public static synchronized Wonder getWonder(){
      if(wonder==null){
          try {
              Thread.sleep(1000);
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
          wonder=new Wonder();
      }
      return wonder;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(()->{
                System.out.println(Wonder.getWonder());
            }).start();
        }
    }
}

但是虽然给方法加锁以后,线程安全解决了,但是效率下去了 ,所以我们可以给代码块加锁,并使用双重判断,再给单例对象使用volatile关键字,防止指令重排生成半成品对象

//懒汉模式
public class Wonder1 {
    public static volatile Wonder1 wonder1;   //防止指令重排出现半成品对象

    private  Wonder1(){};

    public static Wonder1 getWonder1(){
        if(wonder1==null){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //防止多个线程进入到此等待锁释放
            synchronized (Wonder1.class){
                //当上一层的线程获得锁后再次判断是否已经初始化过
                if(wonder1==null){
                    wonder1=new Wonder1();
                }
            }
        }
        return wonder1;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(()->{
                System.out.println(Wonder1.getWonder1());
            }).start();
        }
    }
}

JAVA 中的例子:

Runtime 类
Jdk 中的源码 Runtime 类就是一个单例类,利用 Runtime 类可以启动新的进程或进行相关运行时环境的操作。比如,取得内存空间以及释放垃圾空间。 Runtime 类属于典型的单例设计。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值