单例模式
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。单例模式保证了内存中同时只会存在一个实例对象。
适用场景
- 外部资源:每台计算机有若干个打印机,但只能有一个PrinterSpooler,以避免两个打印作业同时输出到打印机。内部资源:大多数软件都有一个(或多个)属性文件存放系统配置,这样的系统应该有一个对象管理这些属性文件
- Windows的Task Manager(任务管理器)就是很典型的单例模式(这个很熟悉吧),想想看,是不是呢,你能打开两个windows task manager吗? 不信你自己试试看哦~
- windows的Recycle Bin(回收站)也是典型的单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。
- 网站的计数器,一般也是采用单例模式实现,否则难以同步。
- 应用程序的日志应用,一般都何用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加。
- Web应用的配置对象的读取,一般也应用单例模式,这个是由于配置文件是共享的资源。
- 数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源。数据库软件系统中使用数据库连接池,主要是节省打开或者关闭数据库连接所引起的效率损耗,这种效率上的损耗还是非常昂贵的,因为何用单例模式来维护,就可以大大降低这种损耗。
- 多线程的线程池的设计一般也是采用单例模式,这是由于线程池要方便对池中的线程进行控制。
- 操作系统的文件系统,也是大的单例模式实现的具体例子,一个操作系统只能有一个文件系统。
- 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;
}
}
静态内部类和非静态内部类一样,都不会因为外部类的加载而加载,同时静态内部类的加载不需要依附外部类,在使用时才加载