保证一个类仅有一个实例,并提供一个全局访问点
适应场景:
想确保任何情况下都绝对只有一个实例
如:网站的计数器、线程池、数据库的连接池...
优点:
在内存里只有一个实例,减少了内存开销;
可以避免对资源的多重占用;
设置全局访问点,严格控制访问。
缺点:
没有接口,扩展困难;
重点:私有构造器;线程安全;延迟加载;序列化和反序列化安全问题(重要);防止反射攻击(重要)。
代码示例: 1.饿汉式方式1:
package com.demo.design_pattern.creational.singleton;
import java.io.Serializable;
/**
* HungrySingleton
*
* @Description 饿汉式单例模式
*/
public class HungrySingleton implements Serializable {
// private static final HungrySingleton hungrySingleton = new HungrySingleton();
private HungrySingleton() {
//防止单例反射攻击代码
if (hungrySingleton != null) {
throw new RuntimeException("单例构造器禁止反射调用");
}
}
public static HungrySingleton getInstance() {
return hungrySingleton;
}
private Object readResolve() {
return hungrySingleton;
}
}
方式2:
package com.demo.design_pattern.creational.singleton;
import java.io.Serializable;
/**
* HungrySingleton
*
* @Description 饿汉式单例模式
*/
public class HungrySingleton implements Serializable {
// 放在静态代码块中
private static HungrySingleton hungrySingleton = null;
static {
hungrySingleton = new HungrySingleton();
}
private HungrySingleton() {
//防止单例反射攻击代码
if (hungrySingleton != null) {
throw new RuntimeException("单例构造器禁止反射调用");
}
}
public static HungrySingleton getInstance() {
return hungrySingleton;
}
private Object readResolve() {
return hungrySingleton;
}
}
2.懒汉式
package com.demo.design_pattern.creational.singleton;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
* LazySingleton
*
* @Description 懒汉式单例模式 注重延迟加载
*/
public class LazySingleton {
private static LazySingleton lazy = null;
private LazySingleton() {
if (lazy != null) {
throw new RuntimeException("单例构造器禁止反射调用");
}
}
public synchronized static LazySingleton getInstance() {
if (lazy == null) {
lazy = new LazySingleton();
}
return lazy;
}
}
3.懒汉式双重校验
package com.demo.design_pattern.creational.singleton;
/**
* LazyDoubleCheckSingleton
*
* @Description 懒汉式双重校验单例模式
*/
public class LazyDoubleCheckSingleton {
//volatile 保证所有线程可见性
private volatile static LazyDoubleCheckSingleton lazyDoubleCheckSingleton = null;
private LazyDoubleCheckSingleton() {
}
public static LazyDoubleCheckSingleton getInstance() {
if (lazyDoubleCheckSingleton == null) {
synchronized (LazyDoubleCheckSingleton.class) {
if (lazyDoubleCheckSingleton == null) {
lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton();
//1.分配内存给这个对象
//2.初始化对象
//3.设置 lazyDoubleCheckSingleton 指向刚分配的内存地址
}
}
}
return lazyDoubleCheckSingleton;
}
}
4.基于容器实现单例模式
package com.demo.design_pattern.creational.singleton;
import org.apache.commons.lang3.StringUtils;
import java.util.HashMap;
import java.util.Map;
/**
* ContainerSingleton
*
* @Description 容器单例模式
*/
public class ContainerSingleton {
//map看作一个容器
private static Map singletonMap = new HashMap<>();
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);
}
}
5.基于枚举实现单例模式
package com.demo.design_pattern.creational.singleton;
/**
* EnumInstance
*
* @Description 使用枚举实现单例模式
* 主要关注:枚举类型的序列化机制、反射攻击
*/
public enum EnumInstance {
INSTANCE {
@Override
protected void printTest() {
System.out.println("Geely Print Test");
}
};
protected abstract void printTest();
private Object data;
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public static EnumInstance getInstance() {
return INSTANCE;
}
}
6.静态内部类单例模式
package com.demo.design_pattern.creational.singleton;
/**
* StaticInnerClassSingleton
*
* @Description 静态内部类单例模式
*/
public class StaticInnerClassSingleton {
private static class InnerClass {
private static StaticInnerClassSingleton staticInnerClassSingleton = new StaticInnerClassSingleton();
}
public static StaticInnerClassSingleton getInstance() {
return InnerClass.staticInnerClassSingleton;
}
private StaticInnerClassSingleton() {
if (InnerClass.staticInnerClassSingleton != null) {
throw new RuntimeException("静态内部类方式 防止反射攻击单例模式");
}
}
}
7.基于ThreadLocal的单例模式
package com.demo.design_pattern.creational.singleton;
/**
* ThreadLocalInstance
*
* @Description 基于ThreadLocal的单例模式
*/
public class ThreadLocalInstance {
private static final ThreadLocal threadLocalInstanceThreadLocal = new ThreadLocal() {
@Override
protected ThreadLocalInstance initialValue() {
return new ThreadLocalInstance();
}
};
private ThreadLocalInstance() {
}
public static ThreadLocalInstance getInstance() {
return threadLocalInstanceThreadLocal.get();
}
}
8.测试
(1)定义线程类
package com.demo.design_pattern.creational.singleton;
/**
* MyThread
*
* @Description
*/
public class MyThread implements Runnable {
@Override
public void run() {
LazySingleton instance = LazySingleton.getInstance();
// LazyDoubleCheckSingleton instance = LazyDoubleCheckSingleton.getInstance();
//StaticInnerClassSingleton instance = StaticInnerClassSingleton.getInstance();
// HungrySingleton instance = HungrySingleton.getInstance();
/* ContainerSingleton.putInstance("object",new Object());
Object object = ContainerSingleton.getInstance("object");*/
//ThreadLocalInstance instance = ThreadLocalInstance.getInstance();
System.out.println("&&&&&&&&&&&&&&&" + Thread.currentThread().getName() + ":" + instance);
}
}
(2)测试懒汉式单例模式
package com.demo.design_pattern.creational.singleton;
/**
* SingletonTest
*
* @Description
*/
public class SingletonTest {
public static void main(String[] args) throws Exception {
System.out.println("**************测试懒汉式单例模式start");
// LazySingleton instance = LazySingleton.getInstance();
//多线程测试懒汉式单例模式
Thread t1 = new Thread(new MyThread());
Thread t2 = new Thread(new MyThread());
t1.start();
t2.start();
System.out.println("**************测试懒汉式单例模式end");
}
}
测试结果
(3)测试 使用序列化或反序列化破坏单例模式
package com.demo.design_pattern.creational.singleton;
import java.io.*;
/**
* SingletonTest
*
* @Description
*/
public class SingletonTest {
public static void main(String[] args) throws Exception {
//使用序列化或反序列化破坏单例模式
HungrySingleton hungrySingleton = HungrySingleton.getInstance();
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singleton_file"));
oos.writeObject(hungrySingleton);
File singleton_file = new File("singleton_file");
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(singleton_file));
HungrySingleton newInstance = (HungrySingleton) ois.readObject();
System.out.println("!!!!!!!" + hungrySingleton);
System.out.println("!!!!!!!" + newInstance);
System.out.println("hungrySingleton == newInstance 为"+ (hungrySingleton == newInstance));
}
}
测试结果:
(4) 饿汉式 反射攻击解决方案
package com.demo.design_pattern.creational.singleton;
import java.io.*;
import java.lang.reflect.Constructor;
/**
* SingletonTest
*
* @Description
*/
public class SingletonTest {
public static void main(String[] args) throws Exception {
// 饿汉式 反射攻击解决方案
Class hungrySingletonClass = HungrySingleton.class;
Constructor constructor = hungrySingletonClass.getDeclaredConstructor();
constructor.setAccessible(true);
HungrySingleton instance = HungrySingleton.getInstance();
HungrySingleton newInstance =(HungrySingleton) constructor.newInstance();
System.out.println("!!!!!!!" + instance);
System.out.println("!!!!!!!" + newInstance);
System.out.println(instance == newInstance);
}
}
(5)静态内部类方式 防止反射攻击
package com.demo.design_pattern.creational.singleton;
import java.io.*;
import java.lang.reflect.Constructor;
/**
* SingletonTest
*
* @Description
*/
public class SingletonTest {
public static void main(String[] args) throws Exception {
//静态内部类方式 防止反射攻击
Class staticInnerClassSingletonClass = StaticInnerClassSingleton.class;
Constructor constructor = staticInnerClassSingletonClass.getDeclaredConstructor();
constructor.setAccessible(true);
StaticInnerClassSingleton newInstance = (StaticInnerClassSingleton)constructor.newInstance();
StaticInnerClassSingleton instance = StaticInnerClassSingleton.getInstance();
}
}
(6)使用懒汉式 防止反射攻击
package com.demo.design_pattern.creational.singleton;
import java.io.*;
import java.lang.reflect.Constructor;
/**
* SingletonTest
*
* @Description
*/
public class SingletonTest {
public static void main(String[] args) throws Exception {
//使用懒汉式 防止反射攻击
Class objectClass = LazySingleton.class;
Constructor constructor = objectClass.getDeclaredConstructor();
constructor.setAccessible(true);
LazySingleton newInstance = (LazySingleton)constructor.newInstance();
LazySingleton instance = LazySingleton.getInstance();
System.out.println("!!!!!!!" + instance);
System.out.println("!!!!!!!" + newInstance);
System.out.println(instance == newInstance);
}
}
测试结果:
(7)枚举测试序列化机制
package com.demo.design_pattern.creational.singleton;
import java.io.*;
import java.lang.reflect.Constructor;
/**
* SingletonTest
*
* @Description
*/
public class SingletonTest {
public static void main(String[] args) throws Exception {
//枚举测试序列化机制
EnumInstance enumInstance = EnumInstance.getInstance();
enumInstance.setData(new Object());
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singleton_file"));
oos.writeObject(enumInstance);
File singleton_file = new File("singleton_file");
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(singleton_file));
EnumInstance newInstance = (EnumInstance) ois.readObject();
System.out.println("!!!!!!!" + enumInstance.getData());
System.out.println("!!!!!!!" + newInstance.getData());
System.out.println(enumInstance.getData() == newInstance.getData());
}
}
测试结果:
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)