1.实例引入
背景:小成有一个塑料生产厂,但里面只有一个仓库
目的:想用代码来实现仓库的管理
现有做法:建立仓库类和工人类
其中,仓库类里的quantity=商品数量;工人类里有搬运方法MoveIn(int i)和MoveOut(int i)。
出现的问题:经过测试发现,每次工人搬运操作都会新建一个仓库,就是货物都不是放在统一仓库
2.单例模式介绍
说明:实现一个类只有1个实例化对象&提供一个全局访问点
作用:保证一个类只有一个对象,降低对象之间的耦合度
工作原理:在java中,我们通过适用对象(类实例化后)来操作这些类,类实例化是通过它的构造方法进行的,要想实现一个类只有一个实例化对象,就要对类的构造方法下功夫。
public class Singleton{
//1.创建私有变量 ourInstance(用以记录Singleton的唯一实例)
//2.内部进行实例化
private static Singleton ourInstance=new Singleton();
//3.把类的构造方法私有化,不让外部调用构造方法实例化
private Singleton(){
}
//4.定义公有方法提供该类的全剧唯一访问点
//5.外部通过调用getInstance()方法来返回唯一的实例
public static Singleton newInstance(){
return ourInstance;
}
}
3.特点
优点:
提供了对唯一实例的受控访问;
由于在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创建和销毁的对象单例模式无疑可以提高系统的性能;
可以根据实际情况需要,在单例模式的基础上扩展出双列模式,多例模式;
缺点:
单例类职责过重,里面的代码会复杂,违背单一职责原则。
如果实例化的对象长时间不用,会被系统认为垃圾回收,导致对象丢失。
4.实现方式:
初始化单例类即创建单例:饿汉式、枚举类型
按需、延迟创建单例:懒汉式基础实现、同步锁、双重检验锁、静态内部类实现
饿汉式:线程安全,适用 要求初始化速度快,占用内存小
枚举类型:
public enum Singleton{
//定义1个枚举的元素,即为单例类的1个实例
INSTANCE;
// 隐藏了1个空的、私有的 构造方法
// private Singleton () {}
}
// 获取单例的方式:
Singleton singleton = Singleton.INSTANCE;
懒汉式
class Singleton {
// 1. 类加载时,先不自动创建单例
// 即,将单例的引用先赋值为 Null
private static Singleton ourInstance = null;
// 2. 构造函数 设置为 私有权限
// 原因:禁止他人创建实例
private Singleton() {
}
// 3. 需要时才手动调用 newInstance() 创建 单例
public static Singleton newInstance() {
// 先判断单例是否为空,以避免重复创建
if( ourInstance == null){
ourInstance = new Singleton();
}
return ourInstance;
}
}
同步锁(懒汉式改进)
// 写法1
class Singleton {
// 1. 类加载时,先不自动创建单例
// 即,将单例的引用先赋值为 Null
private static Singleton ourInstance = null;
// 2. 构造函数 设置为 私有权限
// 原因:禁止他人创建实例
private Singleton() {
}
// 3. 加入同步锁
public static synchronized Singleton getInstance(){
// 先判断单例是否为空,以避免重复创建
if ( ourInstance == null )
ourInstance = new Singleton();
return ourInstance;
}
}
// 写法2
// 该写法的作用与上述写法作用相同,只是写法有所区别
class Singleton{
private static Singleton instance = null;
private Singleton(){
}
public static Singleton getInstance(){
// 加入同步锁
synchronized(Singleton.class) {
if (instance == null)
instance = new Singleton();
}
return instance;
}
}
双重校验锁(懒汉式的改进)
class Singleton {
private static Singleton ourInstance = null;
private Singleton() {
}
public static Singleton newInstance() {
// 加入双重校验锁
// 校验锁1:第1个if
if( ourInstance == null){ // ①
synchronized (Singleton.class){ // ②
// 校验锁2:第2个 if
if( ourInstance == null){
ourInstance = new Singleton();
}
}
}
return ourInstance;
}
}
// 说明
// 校验锁1:第1个if
// 作用:若单例已创建,则直接返回已创建的单例,无需再执行加锁操作
// 即直接跳到执行 return ourInstance
// 校验锁2:第2个 if
// 作用:防止多次创建单例问题
// 原理
// 1. 线程A调用newInstance(),当运行到②位置时,此时线程B也调用了newInstance()
// 2. 因线程A并没有执行instance = new Singleton();,此时instance仍为空,因此线程B能突破第1层 if 判断,运行到①位置等待synchronized中的A线程执行完毕
// 3. 当线程A释放同步锁时,单例已创建,即instance已非空
// 4. 此时线程B 从①开始执行到位置②。此时第2层 if 判断 = 为空(单例已创建),因此也不会创建多余的实例
静态内部类
class Singleton {
// 1. 创建静态内部类
private static class Singleton2 {
// 在静态内部类里创建单例
private static Singleton ourInstance = new Singleton();
}
// 私有构造函数
private Singleton() {
}
// 延迟加载、按需创建
public static Singleton newInstance() {
return Singleton2.ourInstance;
}
}
// 调用过程说明:
// 1. 外部调用类的newInstance()
// 2. 自动调用Singleton2.ourInstance
// 2.1 此时单例类Singleton2得到初始化
// 2.2 而该类在装载 & 被初始化时,会初始化它的静态域,从而创建单例;
// 2.3 由于是静态域,因此只会JVM只会加载1遍,Java虚拟机保证了线程安全性
// 3. 最终只创建1个单例
网友评论