java 单例模式

本文深入探讨了Java中的单例模式,这是一种创建型设计模式,确保一个类只有一个实例并提供全局访问点。单例模式广泛应用于控制资源访问,如线程池、数据库连接池和配置文件管理。文章列举了多种实现单例的策略,包括懒汉式(线程不安全、线程安全、双重检查锁定)、饿汉式以及内部类实现,并分析了各自的优缺点。此外,还讨论了单例模式在多线程环境下的重要性和适用场景。

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

单例模式

单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。单例模式保证了内存中同时只会存在一个实例对象。

适用场景

  1. 外部资源:每台计算机有若干个打印机,但只能有一个PrinterSpooler,以避免两个打印作业同时输出到打印机。内部资源:大多数软件都有一个(或多个)属性文件存放系统配置,这样的系统应该有一个对象管理这些属性文件
  2. Windows的Task Manager(任务管理器)就是很典型的单例模式(这个很熟悉吧),想想看,是不是呢,你能打开两个windows task manager吗? 不信你自己试试看哦~
  3. windows的Recycle Bin(回收站)也是典型的单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。
  4. 网站的计数器,一般也是采用单例模式实现,否则难以同步。
  5. 应用程序的日志应用,一般都何用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加。
  6. Web应用的配置对象的读取,一般也应用单例模式,这个是由于配置文件是共享的资源。
  7. 数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源。数据库软件系统中使用数据库连接池,主要是节省打开或者关闭数据库连接所引起的效率损耗,这种效率上的损耗还是非常昂贵的,因为何用单例模式来维护,就可以大大降低这种损耗。
  8. 多线程的线程池的设计一般也是采用单例模式,这是由于线程池要方便对池中的线程进行控制。
  9. 操作系统的文件系统,也是大的单例模式实现的具体例子,一个操作系统只能有一个文件系统。
  10. HttpApplication 也是单位例的典型应用。熟悉ASP.Net(IIS)的整个请求生命周期的人应该知道HttpApplication也是单例模式,所有的HttpModule都共享一个HttpApplication实例.

懒汉式

public class MyTest {
    private MyTest() {
    }

    public static MyTest instance;
    
    public static MyTest getInstance() {
        if (instance == null) {
            instance = new MyTest();
        }
        return instance;
    }
}

私有化构造方法,使其只能通过getInstance方法创建对象 ,在被调用的时候才创建。

缺点:多线程环境不适用,如两个现线程都判断了instance=null,那么会创建2个对象。

懒汉式(支持多线程)

public class MyTest {
    private MyTest() {
    }

    public static MyTest instance;

    public static synchronized MyTest getInstance() {
        if (instance == null) {
            instance = new MyTest();
        }
        return instance;
    }
}

给创建方法加锁保证同时只有一个线程可以调用

缺点:每次创建都要加锁,耗时

懒汉式(支持多线程 ,提升效率)(推荐)

public class MyTest {
    private MyTest() {
    }

    public static volatile MyTest instance;

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

只在创建前加锁,提升了后续线程调用时的执行效率。只有第一次创建时个别线程会等待 。

饿汉式(支持多线程 ,推荐)

public class Test {
        private Test() {
        }
        public static Test instance = new Test();
        public static Test getInstance() {
                return instance;
        }
}

缺点:不管什么时候调用,初始化的时候就被创建了。浪费内存

内部类实现(强烈推荐)

public class MyTest {
    private MyTest (){
    }
    private static class SingletonHolder {
        private static final MyTest INSTANCE = new MyTest();
    }
    public static MyTest getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

静态内部类和非静态内部类一样,都不会因为外部类的加载而加载,同时静态内部类的加载不需要依附外部类,在使用时才加载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值