单例模式
描述:
单例模式,顾名思义,保证全局只有一个实例对象,并且提供对该对象的访问方法
特点:
- 类的构造方法私有化
- 私有静态变量
- 提供共有的方法,访问该实例
实现:
Ⅰ 懒汉式
线程不安全;延迟加载
package com.bookmark.designpatterns.singleton;
/**
* @author: hj
* @date: 2020-12-19 14:24
* @description: 1.懒汉式,线程不安全
**/
public class SingletonImpl1 {
//私有变量
private static SingletonImpl1 singletonImpl1;
//构造方法私有化
private SingletonImpl1() {
}
//公有的静态方法
public static SingletonImpl1 getUniqueInstance() {
if (singletonImpl1 == null) { //此处判断线程不安全,存在创建多个实例的可能
singletonImpl1 = new SingletonImpl1();
}
return singletonImpl1;
}
}
Ⅱ 饿汉式
线程安全,但是消耗资源,未使用实例的时候就已经创建出来了
package com.bookmark.designpatterns.singleton;
/**
* @author: hj
* @date: 2020-12-19 15:19
* @description: 饿汉式 - 线程安全,但是比较消耗资源,未使用该实例时就已经创建出来了
**/
public class SingletonImpl2 {
private static SingletonImpl2 singletonImpl2 = new SingletonImpl2();
private SingletonImpl2() {
}
public static SingletonImpl2 getInstance(){
return singletonImpl2;
}
}
Ⅲ 懒汉式
线程安全实现方法,对获取实例的方法加入同步锁,性能较差,不推荐
package com.bookmark.designpatterns.singleton;
/**
* @author: hj
* @date: 2020-12-19 15:37
* @description: 懒汉式 - 线程安全,对方法加锁
**/
public class SingletonImpl3 {
private static SingletonImpl3 singletonImpl3;
private SingletonImpl3() {
}
public static synchronized SingletonImpl3 getInstance() { //在方法上加锁,确保线程安全,但是加入锁后,性能下降,不推荐
if (singletonImpl3 == null) {
singletonImpl3 = new SingletonImpl3();
}
return singletonImpl3;
}
}
Ⅳ 双重检验锁
线程安全, 使用 volatile 关键字防止jvm指令重排
package com.bookmark.designpatterns.singleton;
/**
* @author: hj
* @date: 2020-12-19 15:40
* @description:
* 双重检验锁 - 线程安全
* volatile关键字防止jvm指令重排
**/
public class SingletonImpl4 {
private volatile static SingletonImpl4 singletonImpl4;
private SingletonImpl4() {
}
public static SingletonImpl4 getInstance() {
if (singletonImpl4 == null) {
synchronized (SingletonImpl4.class) {//对实例化部分的代码进行加锁,相较于直接给方法加锁,提升了效率
if (singletonImpl4 == null) {//此处if判断是为了防止多线程进入第一个if判断条件后,导致创建多个实例
singletonImpl4 = new SingletonImpl4();
}
}
}
return singletonImpl4;
}
}
Ⅴ 静态内部类实现
延时加载,线程安全
package com.bookmark.designpatterns.singleton;
/**
* @author: hj
* @date: 2020-12-26 14:21
* @description: 静态内部类实现 涉及到类加载相关的问题 延时加载,线程安全
*
* 1. 父类被加载的时候,SingletonHolder不会被加载,此时并不会占用内存
* 2. 当调用getInstance方法的时候,INSTANCE 才会被初始化
* 3. 由于jvm类加载的机制,保证了该实现的线程安全
**/
public class SingletonImpl5 {
private SingletonImpl5() {
}
private static class SingletonHolder{
private static final SingletonImpl5 INSTANCE = new SingletonImpl5();
}
public static SingletonImpl5 getInstance() {
return SingletonHolder.INSTANCE;
}
}
Ⅵ 枚举实现
线程安全,可以防止反射攻击,多次序列化和反序列化后也不会创建多个实例
package com.bookmark.designpatterns.singleton;
/**
* @author: hj
* @date: 2020-12-26 16:07
* @description: 枚举实现
* 1.线程安全
* 2.可以防止反射攻击 ,其他实现不能保证,需要在构造方法中加入防止多次实例化的代码 --- 反射攻击:通过反射 ,使用setAccessible()方法可以将私有的构造方法方位级别设置为public
* 3.多次序列化和反序列化后,不会创建多个对象; 而其他实现需要使用transient关键字修饰所有的变量
**/
public enum SingletonImpl6 {
/**
* 实例
*/
INSTANCE;
private String objName;
private String getObjName() {
return objName;
}
private void setObjName(String objName) {
this.objName = objName;
}
public static void main(String[] args) {
//单例测试
SingletonImpl6 firstSingleton = SingletonImpl6.INSTANCE;
firstSingleton.setObjName("first name");
System.out.println("firstSingleton = " + firstSingleton.getObjName());
SingletonImpl6 secondSingleton = SingletonImpl6.INSTANCE;
secondSingleton.setObjName("second name");
System.out.println("firstSingleton = " + firstSingleton.getObjName());
System.out.println("secondSingleton = " + secondSingleton.getObjName());
//反射获取实例测试
SingletonImpl6[] enumConstants = SingletonImpl6.class.getEnumConstants();
for (SingletonImpl6 enumConstant : enumConstants) {
System.out.println("objName = " + enumConstant.getObjName());
}
}
}
总结
线程安全:2 ,3 ,4,5,6
可防止反射攻击,序列化和反序列话不会创建多个对象的只有 枚举实现