一. 定义及概念
1. 单例模式是Java中一种常见的设计模式,用于确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
2. 单例设计模式有以下三个特点:
1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。
3. 在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。这些应用都或多或少具有资源管理器的功能。每台计算机可以有若干个打印
机,但只能有一个Printer Spooler,以避免两个打印作业同时输出到打印机中。每台计算机可以有若干通信端口,系统应当集中管理这些通信端口,以避免一个通信端口同时被
两个请求同时调用。总之,选择单例模式就是为了避免不一致状态,避免政出多头。
4. 单例设计模式的组成要素
① 私有的构造方法
② 指向自己实例的静态引用
③ 以自己实例为返回值的公有方法
二. 分类说明
单例设计模式根据实例化对象时机的不同,又分为三种: ①饿汉式单例 ②懒汉式单例 ③登记式单例。
① 饿汉式单例
public class Singleton { // 组成元素1:指向自己实例的私有静态引用 private static final Singleton singleton = new Singleton(); // 组成元素2: 私有的构造方法 private Singleton() { } // 组成元素3:以自己实例为返回值的静态的公有的方法 public static Singleton getInstance() { return singleton; } }
饿汉式在类初始化加载的同时(而不是实例化时)已经创建好一个静态的对象供系统使用,以后不再改变。
问题1:私有构造方法?
将构造方法限定为private,可以防止类在外部被实例化,也就是说,单例类的唯一实只能通过该实例类中方法
得到(getInstance())。
问题2:线性安全?
是的!
② 懒汉式单例
public class Singleton { // 组成元素1:指向自己实例的私有静态引用 private static Singleton singleton; // 组成元素2: 私有的构造方法 private Singleton() { } // 组成元素3:以自己实例为返回值的静态的公有的方法 public static Singleton getInstance() { if(singleton==null){ singleton = new Singleton(); } return singleton; } }
懒汉式单例在调用取得实例方法(getInstance()方法)时才会实例化对象,所以也可以用延迟加载来表示其特点。
与饿汉式不同,懒汉式在多线程下可能会出现安全问题,即可能出现多个Singleton实例,所以我们需要一些措施来保证线程安全。
方法1: 在getInstance方法上加同步
public static synchronized Singleton getInstance() {
if (single == null) {
single = new Singleton();
}
return single;
}
这种方法虽然解决了线程安全问题,但当有多个线程访问就需要频繁判断锁,性能不是太高。
所以有了改进的第二种方法。
方法2:双重检查锁定
public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
}
三. 各方法的优缺点
1. 懒汉式以及饿汉式的区别
饿汉就是类一旦加载,就把单例初始化完成,保证在getInstance时,单例已经存在
而懒汉比较懒,只有调用getInstance时,才初始化实例。
1.线程安全
饿汉式天生线程安全,可以直接使用多线程而不会出现问题
懒汉式本身线程非安全,可以按照上面两种方法改造实现线程安全
2. 资源加载与性能
饿汉式在类创建的同时就实例化一个静态对象出来,不管之后会不会使用这个单例,都会占据一定的内存,但是相应的,在
第一次调用时速度也会更快,因为其资源已经初始化完成。
而懒汉式顾名思义,会延迟加载,在第一次使用该单例的时候才会实例化对象出来,第一次调用时要做初始化,如果要做的
工作比较多,性能上会有些延迟,之后就和饿汉式一样了。
2.单例模式的优点
1.在内存中只有一个对象,节省内存空间
2.避免频繁的创建和销毁对象,提高性能
3.避免对共享资源的多重占用
4.可以进行全局访问
四. 总结
一般在Java中,比较常用的是饿汉式,因为天然线程安全。但懒汉式的各个特点及变形线程安全依然要掌握。