前言
这篇文章主要讲述基于Java语言实现多线程的单例模式。
单例模式的概述
为什么需要单例模式
对于一个软件系统中的某些类而言,只有一个实例很重要,例如一个系统只能有一个窗口管理器或文件系统,一个系统只能有一个集市工具或ID生成器等等。在Windows操作系统中就只能打开一个任务管理器窗口,如下图1所示。如果不使用机智对窗口对象进行唯一化,势必会弹出多个窗口。如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源;如果这些窗口显示的内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符合,这会给用户带来误解,不知道哪一个才是真实的状态。因此有时确保系统中某个对象的唯一性(即一个类只能有一个实例)非常重要。
单例模式的定义
确保一个类只有一个实例,并提供一个全局访问点来访问这个唯一实例。
多线程单例模式的实现
基于饿汉式单例
实例代码
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return instance;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Singleton s1, s2;
s1 = Singleton.getInstance();
s2 = Singleton.getInstance();
if(s1 == s2){
System.out.println("两个对象是相同实例");
}
else{
System.out.println("两个对象是不同实例");
}
}
}
运行截图如下图2
基于懒汉式单例
实例代码
public class Singleton {
private Singleton() {
}
//静态内部类
private static class SingletonHandler {
private final static Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return SingletonHandler.instance;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Singleton s1, s2;
s1 = Singleton.getInstance();
s2 = Singleton.getInstance();
System.out.println("两个对象实例是否相同?");
System.out.println(s1 == s2);
}
}
运行截图如下图3
饿汉式与懒汉式的比较
饿汉式单例类在类加载时就将自己实例化,它的优点在于无需考虑多个线程同时访问的问题,可以确保实例的唯一性;从调用速度和反应时间速度来讲,由于单例对象一开始就得以创建,因此要优于懒汉式单例。但是无论系统在运行时是否需要使用该单例对象,由于在类加载时该对象就需要创建,因此从资源利用效率角度来讲饿汉式单例不及懒汉式单例,而且在系统加载时由于需要创建饿汉式单例对象,加载时间可能会比较长。
懒汉式单例类在第一次使用时创建,无须一直占用系统资源,实现了延迟加载,但是必须要处理多个线程同时访问的问题,特别是当单例类作为资源控制器,在实例化时必然涉及资源初始化,而资源初始化很有可能耗费大量时间,这意味着出现多线程同时首次引用此类的几率比较大,需要通过同步化机制进行控制。
小结
单例模式的主要优点在于提供了对唯一实例的受控访问并可以节约系统资源;其主要缺点在于因为缺少抽象层而难以扩展,且单例类职责过重。
单例模式适用情况包括:系统只需要一个实例对象;客户调用类的单个实例只允许使用一个公共访问点。