1 什么是单例模式?
单例模式是 Java 的设计模式之一。
单例模式设计的类,该类自己负责创建自己的对象,同时确保只有唯一的一个对象被创建。并且该类应提供访问其对象的方式,可以直接访问,不需要实例化该类的对象。
注意:
- 1、单例类只能有一个实例。
- 2、单例类必须自己创建自己的唯一实例。
-
3、单例类必须对外提供该实例的访问方法。
2 什么时候使用单例模式?
-
需要频繁创建的一些类,使用单例可以降低系统的内存压力,减少 GC。
-
某类只要求生成一个对象的时候,如一个班中的班长、每个人的身份证号等。
-
某些类创建实例时占用资源较多,或实例化耗时较长,且经常使用。
-
某类需要频繁实例化,而创建的对象又频繁被销毁的时候,如多线程的线程池、网络连接池等。
-
频繁访问数据库或文件的对象。
-
对于一些控制硬件级别的操作,或者从系统上来讲应当是单一控制逻辑的操作,如果有多个实例,则系统会完全乱套。
-
当对象需要被共享的场合。由于单例模式只允许创建一个对象,共享该对象可以节省内存,并加快对象访问速度。如 Web 中的配置对象、数据库的连接池等。 32
3 单例模式的两种方式
3.1 饿汉式
public class Hugery {
private Hugery(){}//构造方法私有化
private final static Hugery HUGERY = new Hugery();//常量实现唯一实例
public static Hugery getInstance(){//对外提供该实例的访问方法
return HUGERY;
}
}
该模式的特点是类一旦加载就创建一个单例,保证在调用 getInstance 方法之前单例已经存在了。
饿汉式单例在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以是线程安全的,可以直接用于多线程而不会出现问题。
3.2 懒汉式
public class Lazy {
private Lazy(){}//私有化构造方法
private volatile static Lazy lazy;//volatile关键字防止指令重排
public static Lazy getInstance(){
if (lazy==null){
synchronized (Lazy.class){//第一次创建对象时给该类加锁,实现线程安全
if (lazy==null)
lazy = new Lazy();//双重锁检测后才创建对象
}
}
return lazy;
}
}
该模式的特点是类加载时没有生成单例,只有当第一次调用 getlnstance 方法时才去创建这个单例。
多线程程序中,关键字 volatile 和 synchronized可以保证线程安全,但是每次访问时都要同步,会影响性能,且消耗更多的资源。