Full-Stack-Notes/notes/Java_单例设计模式详解.md
2019-07-31 14:39:37 +08:00

194 lines
4.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Java 单例设计模式详解
参考自慕课网课程:[Java设计模式精讲](https://coding.imooc.com/class/270.html):star::star::star::star::star:
#### 1、单例模式的饿汉模式线程安全
缺点:在类初始化时候就会初始化对应的单例类,如果单例类没有被用到且单例类初始化复杂,就不应用这种模式
```java
public class HungrySingleton {
private static final HungrySingleton hungrySingleton;
private HungrySingleton(){
// 如果不加上这个判断,就会被反射攻击
if (hungrySingleton!=null){
throw new RuntimeException("单例模式禁止反射调用!");
}
}
static {
hungrySingleton=new HungrySingleton();
}
public static HungrySingleton getInstance(){
return hungrySingleton;
}
}
```
```java
// 反射攻击
public class ReflectAttack {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
// 反射攻击
Class<HungrySingleton> hungrySingletonClass = HungrySingleton.class;
Constructor<HungrySingleton> constructor = hungrySingletonClass.getDeclaredConstructor();
// 获取可操作权限
constructor.setAccessible(true);
HungrySingleton hungrySingleton = constructor.newInstance();
HungrySingleton instance = HungrySingleton.getInstance();
System.out.println(hungrySingleton==instance);
}
}
```
#### 2.单例模式的懒汉模式(线程不安全)
```java
public class LazySingleton {
private static LazySingleton lazySingleton=null;
private LazySingleton(){
if (lazySingleton!=null){
throw new RuntimeException("单例模式禁止反射调用!");
}
}
// 在多线程下是不安全的
public static LazySingleton getInstance(){
if (lazySingleton!=null){
lazySingleton=new LazySingleton();
}
return lazySingleton;
}
}
```
#### 3.单例模式的懒汉模式(采用双重检查锁,线程安全)
```java
public class LazySingleton {
// 必须要声明为 volatile 防止指令重排序
private static volatile LazySingleton lazySingleton = null;
private LazySingleton() {
if (lazySingleton != null) {
throw new RuntimeException("单例模式禁止反射调用!");
}
}
public static LazySingleton getInstance() {
if (lazySingleton == null) {
synchronized (LazySingleton.class) {
if (lazySingleton == null) {
/*
new对象过程
1.分配内存给这个对象
2.初始化对象
3.设置lazyDoubleCheckSingleton 指向刚分配的内存地址
上述三步会发生指令重排序
*/
lazySingleton = new LazySingleton();
}
}
}
return lazySingleton;
}
}
```
#### 4.使用枚举实现单例(推荐 JVM保证下的单例
**能够防止反射攻击和序列化对单例的破坏**
```java
// 枚举单例模式
public enum EnumInstance {
INSTANCE;
public static EnumInstance getInstance() {
return INSTANCE;
}
}
```
```java
// 测试
public class Test {
public static void main(String[] args) {
EnumInstance instance0 = EnumInstance.INSTANCE;
EnumInstance instance1 = EnumInstance.getInstance();
EnumInstance instance2 = EnumInstance.getInstance();
System.out.println(instance0 == instance1); // true
System.out.println(instance0 == instance2); // true
System.out.println(instance1 == instance2); // true
}
}
```
```java
public enum EnumInstance {
INSTANCE;
private String data;
// 可以增加对应的方法
public void setData(String data) {
this.data = data;
}
public String getData() {
return data;
}
public static EnumInstance getInstance() {
return INSTANCE;
}
}
```
#### 5.容器式单例(不常用)
```java
public class ContainerSingleton {
private ContainerSingleton(){
}
private static Map<String,Object> singletonMap = new HashMap<String,Object>();
public static void putInstance(String key,Object instance){
if(StringUtils.isNotBlank(key) && instance != null){
if(!singletonMap.containsKey(key)){
singletonMap.put(key,instance);
}
}
}
public static Object getInstance(String key){
return singletonMap.get(key);
}
}
```