单例模式
- 定义:保障一个类仅有一个实例,并提供一个全局拜访点
- 类型:创立型
- 实用场景:想确保任何状况下都相对只有一个实例
长处:
- 在内存里只有一个实例,缩小了内存开销
- 能够防止对资源的多重占用
- 设置全局拜访点,严格控制拜访
- 毛病:没有接口,扩大艰难
重点:
- 公有结构器
- 线程平安
- 提早加载
- 序列化和反序列化平安
- 反射
- Double Check
动态外部类:
实用技能
- 反编译
- 内存原理
多线程Debug
相干设计模式
- 单例模式和工厂模式
- 单例模式和享元模式
代码示例
懒汉式
public class LazySingleton { private static LazySingleton lazySingleton; private LazySingleton() { } /** * synchronized(同步锁比拟耗费资源) * 加在静态方法上:锁的是类的class文件 * 加在一般办法上:锁的是堆内存中的对象 * @return */ public synchronized static LazySingleton getInstance(){//懒汉式 if(lazySingleton==null){ lazySingleton = new LazySingleton(); } return lazySingleton; }}
public class T implements Runnable{ @Override public void run() { LazySingleton lazySingleton = LazySingleton.getInstance(); System.out.println(Thread.currentThread()+" "+lazySingleton); }}
测试类:
public class Test { public static void main(String[] args) {// LazySingleton lazySingleton = LazySingleton.getInstance(); Thread t1 = new Thread(new T()); Thread t2 = new Thread(new T()); t1.start(); t2.start(); System.out.println("program end");/* for (int i = 0; i < 10; i++) { new Thread(new T()).start(); }*/ }}
双重校验(改良):
public class LazyDoubleCheckSingleton { // volatile多线程运行代码执行时重排序引起的问题(不容许重排序) private volatile static LazyDoubleCheckSingleton lazyDoubleCheckSingleton; private LazyDoubleCheckSingleton() { } public static LazyDoubleCheckSingleton getInstance(){//懒汉式 if(lazyDoubleCheckSingleton==null){ synchronized (LazyDoubleCheckSingleton.class){ if (lazyDoubleCheckSingleton==null){ lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton(); } } } return lazyDoubleCheckSingleton; }}
基于类初始化的提早加载解决方案:
/** * 基于类初始化的提早加载解决方案 */public class StaticInnerClassSingleton { private StaticInnerClassSingleton() { } private static class InnerClass{ private static StaticInnerClassSingleton staticInnerClassSingleton = new StaticInnerClassSingleton(); } public static StaticInnerClassSingleton getInstance(){ return InnerClass.staticInnerClassSingleton; }}
public class T implements Runnable{ @Override public void run() {// LazySingleton lazySingleton = LazySingleton.getInstance();// LazyDoubleCheckSingleton lazyDoubleCheckSingleton = LazyDoubleCheckSingleton.getInstance(); StaticInnerClassSingleton staticInnerClassSingleton = StaticInnerClassSingleton.getInstance(); System.out.println(Thread.currentThread()+" "+staticInnerClassSingleton); }}
饿汉式
public class HungrySingleton {//饿汉式 // 申明为final的变量必须在类加载时实现赋值 private static final HungrySingleton hungrySingleton; static{ hungrySingleton = new HungrySingleton(); } private HungrySingleton() { } public static HungrySingleton getInstance() { return hungrySingleton; }}
序列化毁坏单例模式
public class HungrySingleton implements Serializable {//饿汉式 // 申明为final的变量必须在类加载时实现赋值 private static final HungrySingleton hungrySingleton; static{ hungrySingleton = new HungrySingleton(); } private HungrySingleton() { } public static HungrySingleton getInstance() { return hungrySingleton; } /** * 如果不写该办法,反序列化时会通过反射创立一个新的对象并返回,与序列化的对象不是同一对象。 * 若写了该办法,则反序列化时,尽管通过反射创立一个新的对象,但会返回该对象。 * @return */ private Object readResolve(){ return hungrySingleton; }}
public class Test { public static void main(String[] args) throws IOException, ClassNotFoundException { HungrySingleton instance = HungrySingleton.getInstance(); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singleton_file")); oos.writeObject(instance); File file = new File("singleton_file"); ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file)); HungrySingleton newInstance = (HungrySingleton) ois.readObject(); System.out.println(instance); System.out.println(newInstance); System.out.println(instance==newInstance); }}
反射攻打解决方案
public class HungrySingleton implements Serializable {//饿汉式 // 申明为final的变量必须在类加载时实现赋值 private static final HungrySingleton hungrySingleton; static{ hungrySingleton = new HungrySingleton(); } private HungrySingleton() { if (hungrySingleton!=null){ throw new RuntimeException("单例结构器禁止反射调用"); } } public static HungrySingleton getInstance() { return hungrySingleton; }}
public class StaticInnerClassSingleton { private StaticInnerClassSingleton() { if (InnerClass.staticInnerClassSingleton!=null){ throw new RuntimeException("单例结构器禁止反射调用"); } } private static class InnerClass{ private static StaticInnerClassSingleton staticInnerClassSingleton = new StaticInnerClassSingleton(); } public static StaticInnerClassSingleton getInstance(){ return InnerClass.staticInnerClassSingleton; }}
public class LazySingleton { private static LazySingleton lazySingleton; private LazySingleton() { if (lazySingleton!=null){ throw new RuntimeException("单例结构器禁止反射调用"); } } public synchronized static LazySingleton getInstance(){//懒汉式 if(lazySingleton==null){ lazySingleton = new LazySingleton(); } return lazySingleton; }}
测试类:
/***能够解决饿汉式的反射攻打,但没有解决懒汉式的反射攻打。*/public class Test { public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {// Class hungrySingletonClass = HungrySingleton.class;// Class objectClass = StaticInnerClassSingleton.class; Class objectClass = LazySingleton.class; Constructor constructor = objectClass.getDeclaredConstructor(); constructor.setAccessible(true);// HungrySingleton instance = HungrySingleton.getInstance();// HungrySingleton newInstance = (HungrySingleton) constructor.newInstance();// StaticInnerClassSingleton instance = StaticInnerClassSingleton.getInstance();// StaticInnerClassSingleton newInstance = (StaticInnerClassSingleton) constructor.newInstance(); LazySingleton newInstance = (LazySingleton) constructor.newInstance(); LazySingleton instance = LazySingleton.getInstance(); System.out.println(instance); System.out.println(newInstance); System.out.println(instance==newInstance); }}
Enum枚举单例
Jad:反编译工具
序列化
public class Test { public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { // HungrySingleton instance = HungrySingleton.getInstance(); EnumInstance instance = EnumInstance.getInstance(); instance.setData(new Object()); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singleton_file")); oos.writeObject(instance); File file = new File("singleton_file"); ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));// HungrySingleton newInstance = (HungrySingleton) ois.readObject(); EnumInstance newInstance = (EnumInstance) ois.readObject(); System.out.println(instance.getData()); System.out.println(newInstance.getData()); System.out.println(instance.getData()==newInstance.getData()); }}
反射
public enum EnumInstance { INSTANCE{ protected void printTest(){ System.out.println("Feyl 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; }}
public class Test { public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { Class objectClass = EnumInstance.class; Constructor constructor = objectClass.getDeclaredConstructor(String.class,int.class); constructor.setAccessible(true); EnumInstance instance = (EnumInstance) constructor.newInstance("Feyl",666); // EnumInstance instance = EnumInstance.getInstance();// instance.printTest(); }}
容器单例
public class ContainerSingleton {// 线程不平安 private static Map<String,Object> singletonMap = new HashMap<>(); private ContainerSingleton() { } 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); }}
public class T implements Runnable{ @Override public void run() { ContainerSingleton.putInstance("object",new Object()); Object instance = ContainerSingleton.getInstance("object"); System.out.println(Thread.currentThread()+" "+instance); }}
测试类:
public class Test { public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { Thread t1 = new Thread(new T()); Thread t2 = new Thread(new T()); t1.start(); t2.start(); System.out.println("program end"); }}
TreadLocal线程单例
public class ThreadLocalInstance { private static final ThreadLocal<ThreadLocalInstance> threadLocalInstance = new ThreadLocal<ThreadLocalInstance>(){ @Override protected ThreadLocalInstance initialValue() { return new ThreadLocalInstance(); } }; private ThreadLocalInstance(){ } public static ThreadLocalInstance getInstance() { return threadLocalInstance.get(); }}
public class T implements Runnable{ @Override public void run() { ThreadLocalInstance instance = ThreadLocalInstance.getInstance(); System.out.println(Thread.currentThread()+" "+instance); }}
测试类同上
“以空间换工夫”:ThreadLocal 为每一个线程创立一个空间,各个线程获取其独有的对象。