Author : HuiFer
Git-Repo: JavaBook-src
public class SimpleSingleton { public static SimpleSingleton lazy = null; private SimpleSingleton() { } public static SimpleSingleton getInstance() { if (lazy == null) { lazy = new SimpleSingleton(); } return lazy; } }
public class ExecutorThread implements Runnable { @Override public void run() { SimpleSingleton instance = SimpleSingleton.getInstance(); System.out.println("当前线程 " + Thread.currentThread().getName() + ",当前对象" + instance); } }
public class SimpleSingletonTest { public static void main(String[] args) { Thread t1 = new Thread(new ExecutorThread()); Thread t2 = new Thread(new ExecutorThread()); t1.start(); t2.start(); } }
切换到线程模式debug
下方会出现一个debug 窗口
我们将两个线程都执行到 断点
根据代码我们可以知道只要有先后顺序就会得到一个单例对象.一旦同时进入就可能得到两个对象 。 通过debug 进行论证
让第一个线程进入 if
语句
让第二个线程进入
此时观察输出结果
结束 当前线程 Thread-1,当前对象com.huifer.design.singleton.nw.SimpleSingleton@52fd9092 当前线程 Thread-0,当前对象com.huifer.design.singleton.nw.SimpleSingleton@5a28dc04
因此上面的写法是线程不安全的
再次debug
第一个线程进入
第二个线程不允许进入
线程状态 MONITOR 监听状态
第一个线程执行完成后才会变成 RUNNING
public synchronized static SimpleSingleton getInstance01() { if (lazy == null) { synchronized (SimpleSingleton.class) { if (lazy == null) { lazy = new SimpleSingleton(); } } } return lazy; }
通过两张图我们可以发现 Thread-0 状态未 MONITOR 在等待 Thread-1 执行完成 , 切换到Thtread-1 走完
Thread-0 也走完
此时输出结果
当前线程 Thread-1,当前对象com.huifer.design.singleton.nw.SimpleSingleton@63668bdb 当前线程 Thread-0,当前对象com.huifer.design.singleton.nw.SimpleSingleton@63668bdb
public class LazyInnerClassSingleton { private LazyInnerClassSingleton() { } public static LazyInnerClassSingleton getInstance() { return LazyObj.lazy; } private static class LazyObj { public static final LazyInnerClassSingleton lazy = new LazyInnerClassSingleton(); } }
类加载的顺序
public class LazyInnerClassSingletonTest { public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { Class<LazyInnerClassSingleton> clazz = LazyInnerClassSingleton.class; Constructor<LazyInnerClassSingleton> declaredConstructor = clazz.getDeclaredConstructor(null); declaredConstructor.setAccessible(true); LazyInnerClassSingleton lazyInnerClassSingleton = declaredConstructor.newInstance(null); // 输出地址 System.out.println(lazyInnerClassSingleton); // 输出地址 System.out.println(LazyInnerClassSingleton.getInstance()); } }
com.huifer.design.singleton.nw.LazyInnerClassSingleton@6f94fa3e com.huifer.design.singleton.nw.LazyInnerClassSingleton@5e481248
最简单的方案 , 不允许构造即可
private LazyInnerClassSingleton() { throw new RuntimeException("ex"); }
public class SerializableSingleton implements Serializable { private static final SerializableSingleton singleton = new SerializableSingleton(); private SerializableSingleton() { } public static SerializableSingleton getInstance() { return singleton; } }
public class SerializableSingletonTest { public static void main(String[] args) { SerializableSingleton s1 = null; SerializableSingleton s2 = SerializableSingleton.getInstance(); FileOutputStream fos = null; try { // 写出去 fos = new FileOutputStream("SerializableSingleton.obj"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(s2); oos.flush(); oos.close(); // 读进来 FileInputStream fis = new FileInputStream("SerializableSingleton.obj"); ObjectInputStream ois = new ObjectInputStream(fis); s1 = (SerializableSingleton) ois.readObject(); ois.close(); System.out.println(s1); System.out.println(s2); } catch (Exception e) { e.printStackTrace(); } } }
com.huifer.design.singleton.nw.SerializableSingleton@6e8cf4c6 com.huifer.design.singleton.nw.SerializableSingleton@355da254
private Object readResolve() { return singleton; }
ois.readObject()
java.io.ObjectInputStream#readObject0
java.io.ObjectInputStream#readOrdinaryObject
这里 desc.newInstance()
创建了一个因此不相同
同一个方法继续往下走
这里在判断是否存在 readResolve
方法