单例模式实现
一.实现双重校验锁
public class Singleton {
private volatile static Singleton singleton;
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
特点:通过关键字synchronized保证高并发下,初始化对象为单例。缺点性能较差,对象属性需要volatile进行修饰防止编译期间指令重排序,导致返回对象为null。
二.通过类加载机制
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
或
public class Singleton {
private Singleton instance = null;
static {
instance = new Singleton();
}
private Singleton (){}
public static Singleton getInstance() {
return this.instance;
}
}
特点:饿汉模式,ClassLoader的loadClass方法在加载类的时候使用了synchronized关键字。也正是因为这样, 除非loadClass被重写,这个方法默认在整个装载过程中都是同步的(线程安全的),保证方法调用前已被初始化一次。
三.利用内部类
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
特点:使用静态内部类,借助了classloader来实现了线程安全,这与饿汉模式有着异曲同工之妙,但是他有兼顾了懒汉模式的lazy-loading功能,相比较之下,有很大优势。
四.利用枚举
public enum Singleton {
INSTANCE;
public void whateverMethod() {
}
}
特点:解决通过反序列化导致单例破坏,代码简洁。
五.通过CAS
public class Singleton {
private static final AtomicReference<Singleton> INSTANCE = new AtomicReference<Singleton>();
private Singleton() {}
public static Singleton getInstance() {
for (;;) {
Singleton singleton = INSTANCE.get();
if (null != singleton) {
return singleton;
}
singleton = new Singleton();
if (INSTANCE.compareAndSet(null, singleton)) {
return singleton;
}
}
}
}
特点:不通过锁的机制。
问题:单例的破坏
public class Test {
public static void main(String[] args) throws FileNotFoundException,
ClassNotFoundException {
// 获取单例对象
Eagersingleton instance = Eagersingleton.getInstance();
// 通过反序列化读取对象
Eagersingleton instance2 = null;
try {
ObjectOutputStream oossStream = new ObjectOutputStream(
new FileOutputStream("D:/EagersingletonTest.txt"));
// 通过序列化把对象写到文件中
oossStream.writeObject(instance);
oossStream.flush();
oossStream.close();
// 读取文件的对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
"D:/EagersingletonTest.txt"));
instance2 = (Eagersingleton) ois.readObject();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(instance);
System.out.println(instance2);
}
}
/**
* @Descrption
* @ClassName Eagersingleton
* @Author qiu_lijun
* @Date 2019/5/23 17:53
* @Version 1.0
*/
public class Eagersingleton implements Serializable {
private static final long serialVersionUID = 888L;
private static Eagersingleton m_instance = new Eagersingleton();// 初始化时已经自行实例化
// 私有默认构造方法
private Eagersingleton() {
}
// 静态工厂方法
public static Eagersingleton getInstance() {
return m_instance;
}
/* public Object readResolve() {
return m_instance;
}*/
}
在调用readObject方法中,会利用反射回去对象实例。假如为在类中定义readResolve方法,就会返回一个新的对象。导致单例模式被破坏。解决方法重写readResolve方法。