单例模式
设备控制,一次只存在一个实例
动机
在正常情况下,一个计算机只能打开唯一一个任务管理器
确保一个类有一个实例且易于被访问
让类自身创建和保存他唯一的实例
定义
- 对象创建型模式
- 确保某一个类只有一个实例
- 必须自行创建实例——不需要用户生成
- 向整个系统提供这个实例
结构
单例:自己关联自己,将单例聚合到自己这个类当中,只有一个单例,因此不看作时组合关系
分析
- 构造函数必须私有化:防止其他用户实例化一个类
- 静态私有成员变量(自身类型):单例本身
- 静态公有的工厂方法:获取私有的单例
饿汉式单例类
什么都事先创建好了
-
声明就是实例化
-
定义为final类型
-
特点:
-
资源利用率低,加载时间长
-
无需考虑多线程问题
-
调用速度优于懒汉模式
-
懒汉式单例类
使用时才实例化
-
声明时定义为空,用户使用时才实例化,用getInstance()才实例化
-
特点:存在多线程调用不安全问题,在实例化的时候需要较长时间,其他进程
-
解决:使用synchronized关键字进行互斥访问
- 锁方法
效率低
-
锁代码段(问题出在于if(instance == null))
上面仍不安全,依然存在同一时间两个线程进入同一个if语句,因此要用双重检查锁定
静态内部类
最优的解决方法
- 特点
- 延迟加载
- 处理多线程问题
- 通过双重检查锁定等机制会影响系统进程
实例
PrintSpoolerSingleton类
public class PrintSpoolerSingleton
{
private static PrintSpoolerSingleton instance=null;
private PrintSpoolerSingleton()
{
}
public static PrintSpoolerSingleton getInstance() throws PrintSpoolerException
{
if(instance==null)
{
System.out.println("创建打印池!");
instance=new PrintSpoolerSingleton();
}
else
{
throw new PrintSpoolerException("打印池正在工作中!");
}
return instance;
}
public void manageJobs()
{
System.out.println("管理打印任务!");
}
}
PrintSpoolerException类
public class PrintSpoolerException extends Exception
{
public PrintSpoolerException(String message)
{
super(message);
}
}
Client类
public class Client
{
public static void main(String a[])
{
PrintSpoolerSingleton ps1,ps2;
try
{
ps1=PrintSpoolerSingleton.getInstance();
ps1.manageJobs();
}
catch(PrintSpoolerException e)
{
System.out.println(e.getMessage());
}
System.out.println("--------------------------");
try
{
ps2=PrintSpoolerSingleton.getInstance();
ps2.manageJobs();
}
catch(PrintSpoolerException e)
{
System.out.println(e.getMessage());
}
}
}
优点
- 提供了对唯一实例等受控访问
- 节约资源,提高性能
- 允许可变数目的实例(多例类),但每个实例还是只有一个——池化技术
缺点
- 扩展困难:没有抽象层
- 单例类指责过重
- java有自动回收机制,因此会导致单例类的丢失
适用场景
- 只需一个实例对象或消耗太大只允许创建一个对象
- 只允许一个公共访问点访问——getInstance()一个访问点:进行权限控制