Singleton { @SuppressWarnings("unchecked") public static <T extends Singleton> T getInstance(Class<T> clazz) { Singleton singleton; Lock lock; (lock = GLOBAL_LOCK.readLock()).lock(); try { singleton = CACHE.get(clazz); } finally { lock.unlock(); } if (singleton == null) { (lock = GLOBAL_LOCK.writeLock()).lock(); try { singleton = (T)CACHE.get(clazz); if (singleton == null) { singleton = (T)createInstance(clazz); CACHE.put(clazz, singleton); } } finally { lock.unlock(); } } return (T)singleton; } protected  Singleton(); @SuppressWarnings("unchecked") static T getInstance(Class<T> clazz);  }
@Test public void testInvokeGetInstance() { A a1 = A.getInstance(); A a2 = A.getInstance(); Assert.assertSame(a1, a2); }
@Test(expected = IllegalProgramException.class) public void testInvokeConstructor() { B.getInstance(); }
@Test public void testInvokeNestedGetInstance() { C c1 = C.getInstance(); C c2 = C.getInstance(); Assert.assertSame(c1, c2); }
@Test public void testSerialization() throws IOException, ClassNotFoundException { D d = D.getInstance(); byte[] buffer; try (ByteArrayOutputStream bout = new ByteArrayOutputStream(); ObjectOutputStream oout = new ObjectOutputStream(bout)) { oout.writeObject(d); oout.flush(); buffer = bout.toByteArray(); } D deserializedD; try (ByteArrayInputStream bin = new ByteArrayInputStream(buffer); ObjectInputStream oin = new ObjectInputStream(bin)) { deserializedD = (D)oin.readObject(); } Assert.assertSame(d, deserializedD); Assert.assertSame(d, deserializedD.self); }
@Test public void testWrapperSerialization() throws IOException, ClassNotFoundException { D d = D.getInstance(); byte[] buffer; try (ByteArrayOutputStream bout = new ByteArrayOutputStream(); ObjectOutputStream oout = new ObjectOutputStream(bout)) { oout.writeObject(new DWrapper(d)); oout.flush(); buffer = bout.toByteArray(); } D deserializedD; try (ByteArrayInputStream bin = new ByteArrayInputStream(buffer); ObjectInputStream oin = new ObjectInputStream(bin)) { deserializedD = ((DWrapper)oin.readObject()).getValue(); } Assert.assertSame(d, deserializedD); Assert.assertSame(d, deserializedD.self); }