第一种方式:同步实现
package design.pattern.singleton;
/**
* 同步保证线程安全,如果并发严重,会导致性能问题
*
* @author SunOlny
*
*/
public class SingletonStrategyTwo {
private static SingletonStrategyTwo singletonStrategyTwo = null;
private SingletonStrategyTwo() {
}
public static synchronized SingletonStrategyTwo getInsttance() {
if (singletonStrategyTwo == null) {
singletonStrategyTwo = new SingletonStrategyTwo();
}
return singletonStrategyTwo;
}
}
第二种实现:利用加载器的特性
package design.pattern.singleton;
import java.io.Serializable;
/**
* classloader机制能保证线程安全但是无法实现懒加载
*
* @author SunOnly
*
*/
public class SingletonStrategyStaticAttribute implements Serializable {
/**
*
*/
private static final long serialVersionUID = 6319892805778631527L;
private static SingletonStrategyStaticAttribute sinletonStrategyOne = new SingletonStrategyStaticAttribute();
private SingletonStrategyStaticAttribute() {
}
public static SingletonStrategyStaticAttribute getInstance() {
return sinletonStrategyOne;
}
}
第三种方式:解决懒加载的问题,我们使用内部的静态类进行优化
package design.pattern.singleton;import java.io.Serializable;
/**使用内部类初始化单例,让其形成懒加载
* @author SunOlny
*
*/
public class SingletonStartegyInnerClass implements Serializable {
/**
*
*/
private static final long serialVersionUID = 4458426835180723296L;
private SingletonStartegyInnerClass() {
}
private static class Handler {
private static final SingletonStartegyInnerClass singletonStartegyInnerClass = new SingletonStartegyInnerClass();
}
public static SingletonStartegyInnerClass getInstance() {
return Handler.singletonStartegyInnerClass;
}
}
package design.pattern.singleton;
/**
*
* 双重验证模式,只能是J2SE1.5之后才能保证线程安全
*
* @author SunOlny
*
*/
public class SingletonStrategyThree {
private static volatile SingletonStrategyThree singletonStrategyThree = null;
private SingletonStrategyThree() {
}
public static SingletonStrategyThree getInsttance() {
if (singletonStrategyThree == null) {
synchronized (SingletonStrategyThree.class) {
if (singletonStrategyThree == null) {
singletonStrategyThree = new SingletonStrategyThree();
}
}
}
return singletonStrategyThree;
}
}
上面的方式如果是有实现序列化,那么反序列化时就无法保证类的单例特性了。使用反射创建对应时也无法保证单例的特性。
解决反序列化的问题需要实现一个接口readResolve
package design.pattern.singleton;
import java.io.Serializable;
/**
* 使用内部类初始化单例,让其形成懒加载
*
* @author SunOlny
*
*/
public class SingletonStartegyInnerClass implements Serializable {
/**
*
*/
private static final long serialVersionUID = 4458426835180723296L;
private SingletonStartegyInnerClass() {
}
private static class Handler {
private static final SingletonStartegyInnerClass singletonStartegyInnerClass = new SingletonStartegyInnerClass();
}
public static SingletonStartegyInnerClass getInstance() {
return Handler.singletonStartegyInnerClass;
}
/**
* 解决反序列化单例问题
*
* @return
*/
public Object readResolve() {
return Handler.singletonStartegyInnerClass;
}
}
要解决反射创建,可以使用枚举天生的单例特性。
package design.pattern.singleton;
/**
* @author SunOlny
*
*/
public enum SingletonStartegyEnum {
instance {
public void execute() {
System.out.println("execute");
}
};
public abstract void execute();
}
package design.pattern.singleton;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import junit.framework.Assert;
import org.junit.Test;
/**
* 测试单例
*
* @author SunOlny
*
*/
public class TestSingleton {
/**
* 未实现readResolve接口,反序列化不能保证单例
*
* @throws ClassNotFoundException
*/
@Test
public void testSingletonSerializableUnReadResolve() throws ClassNotFoundException {
try {
SingletonStrategyStaticAttribute a = SingletonStrategyStaticAttribute.getInstance();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(a);
ByteArrayInputStream bip = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bip);
SingletonStrategyStaticAttribute b = (SingletonStrategyStaticAttribute) ois.readObject();
System.out.println(a == b);
Assert.assertEquals(false, a == b);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 实现了readResolve接口,反序列化能保证单例
*
* @throws ClassNotFoundException
*/
@Test
public void testSingletonSerializableReadResolve() throws ClassNotFoundException {
try {
SingletonStartegyInnerClass a = SingletonStartegyInnerClass.getInstance();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(a);
ByteArrayInputStream bip = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bip);
SingletonStartegyInnerClass b = (SingletonStartegyInnerClass) ois.readObject();
System.out.println(a == b);
Assert.assertEquals(true, a == b);
} catch (IOException e) {
e.printStackTrace();
}
}
}
执行结果
true
false