单例模式
在有些系统中,为了节省内存资源、保证数据内容的一致性,对某些类要求只能创建一个实例,这就是所谓的单例模式。
单例模式的定义与特点
单例(Singleton)模式的定义:指一个类只有一个实例,且该类能自行创建这个实例的一种模式。例如,Windows 中只能打开一个任务管理器,这样可以避免因打开多个任务管理器窗口而造成内存资源的浪费,或出现各个窗口显示内容的不一致等错误。
在计算机系统中,还有 Windows 的回收站、操作系统中的文件系统、多线程中的线程池、显卡的驱动程序对象、打印机的后台处理服务、应用程序的日志对象、数据库的连接池、网站的计数器、Web 应用的配置对象、应用程序中的对话框、系统中的缓存等常常被设计成单例。
单例模式有 3 个特点:
- 单例类只有一个实例对象;
- 该单例对象必须由单例类自行创建;
- 单例类对外提供一个访问该单例的全局访问点;
单例模式的结构与实现
单例模式是设计模式中最简单的模式之一。通常,普通类的构造函数是公有的,外部类可以通过“new 构造函数()”来生成多个实例。但是,如果将类的构造函数设为私有的,外部类就无法调用该构造函数,也就无法生成多个实例。这时该类自身必须定义一个静态私有实例,并向外提供一个静态的公有函数用于创建或获取该静态私有实例。
单例模式的结构和实现
单例模式是设计模式中最简单的模式之一。通常,普通类的构造函数是公有的,外部类可以通过“new 构造函数()”来生成多个实例。但是,如果将类的构造函数设为私有的,外部类就无法调用该构造函数,也就无法生成多个实例。这时该类自身必须定义一个静态私有实例,并向外提供一个静态的公有函数用于创建或获取该静态私有实例。
单例模式的结构
- 单例类:包含一个实例且能自行创建这个实例的类
- 访问类:使用单例的类
懒汉方式,等你要用我再创建。第一次有访问类调用get方法时,判断当前实例为空,那么就创建一个新的
/**
* 懒汉
* 该模式的特点是类加载时没有生成单例,只有当第一次调用 getlnstance 方法时才去创建这个单例。
*/
public class LazySingleton {
/**
* volatile:
* 当一个变量定义为 volatile 之后,将具备两种特性:
* 1.保证此变量对所有的线程的可见性,这里的“可见性”,当一个线程修改了这个变量的值,volatile 保证了新值能立即同步到主内存,
* 以及每次使用前立即从主内存刷新。但普通变量做不到这点,普通变量的值在线程间传递均需要通过主内存(详见:Java内存模型)来完成。
* <p>
* 2.禁止指令重排序优化。有volatile修饰的变量,赋值后多执行了一个“load addl $0x0, (%esp)”操作,
* 这个操作相当于一个内存屏障(指令重排序时不能把后面的指令重排序到内存屏障之前的位置),
* 只有一个CPU访问内存时,并不需要内存屏障;(什么是指令重排序:是指CPU采用了允许将多条指令不按程序规定的顺序分开发送给各相应电路单元处理)
* <p>
* 读性能上和普通变量基本一致,但是写性能会下降
* <p>
* 保证 instance 在所有线程中同步
* <p>
* 第一步:定义实例为空
*/
private static volatile LazySingleton lazySingleton = null;
/**
* 第二步:构造方法私有化
*/
private LazySingleton(){ }
/**
* get方法
* 第三步:提供一个对外的get方法,在实例为null时new 一个对象
*
* @return
*/
public static synchronized LazySingleton getLazySingleton() {
if (lazySingleton == null)
lazySingleton = new LazySingleton();
return lazySingleton;
}
}
/**
* 饿汉
*/
public class HungrySingleton {
/**
* 第一步:直接定义一个新对象
*/
private static final HungrySingleton hungrySingleton = new HungrySingleton();
/**
* 第二步:构造方法私有化
*/
private HungrySingleton() {
}
/**
* get方法
* 第三步:提供一个对外get方法,直接返回,不进行实例的创建
*
* @return
*/
public static synchronized HungrySingleton getHungrySingleton() {
return hungrySingleton;
}
}