众所周知,一般使用java实现单例模式有两种方法,分别为急切式(饥饿式)和双重加锁式,急切式就是在声明时即创建,这样在类加载时就已经创建好了,即时我们可能并不不需要它,它的生命周期是永久的,造成内存泄漏的可能!第二种方式是lazy的,只有在使用时创建,实现了延迟加载。代码为
1.急切式
class Singleton {
private final static Singleton instance = new Singleton();
private Singleton(){
}
public static Singleton getInstance() {
return instance;
}
}
2. 双重加锁式
class Singleton {
private volatile static Singleton instance = null;
private Singleton(){
}
public static Singleton getInstance() {
if (instance == null) {
synchronized(Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
还有一种方法是使用内部类的方法,这主要为克服方法1中的问题,既能实现延迟加载,又能保证线程安全,而且性能不错。代码为:
class Singleton {
private Singleton() {
}
private static class Holder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return Holder.INSTANCE;
}
}
以上方法都是通过使用private构造方法来阻止外部直接创建对象,但如果使用反射机制,则不能保证实例的唯一性了!!!
public class SingletonDemo {
//@SuppressWarnings("unchecked")
//public static T newInstance(Class> cl) {
// T t = null;
// try {
// t = (T)cl.newInstance(); /* 只能调用public构造方法 */
// } catch(Exception e) {
// e.printStackTrace();
// }
// return t;
//}
@SuppressWarnings("unchecked")
public static T newInstance(Class> cl) {
T t = null;
try {
Constructor> constructor = cl.getDeclaredConstructor();
constructor.setAccessible(true);
t = (T)constructor.newInstance();
} catch(Exception e) {
e.printStackTrace();
}
return t;
}
@SuppressWarnings("unchecked")
public static T newInstance(Class> cl, Class>...args) {
T t = null;
try {
Constructor> constructor = cl.getDeclaredConstructor(args);
constructor.setAccessible(true);
t = (T)constructor.newInstance("name", 1);
} catch(Exception e) {
e.printStackTrace();
}
return t;
}
public static void main(String[] args) {
Singleton instance = Single.INSTANCE;
Singleton s1 = newInstance(Singleton.class, String.class, int.class);
Singleton s2 = newInstance(Singleton.class, String.class, int.class);
//Tmp t1 = newInstance(Tmp.class);
//Tmp t2 = newInstance(Tmp.class);
//System.out.println(s1 == s2);
//System.out.println(t1 == t2);
}
}
Joshua Bloch (Effect java 作者)提出一种新的方法实现单例模式,就是使用Enum(其实也是类,一种特殊的类,构造方法必须是private ,final的)!如下:
enum Singleton {
INSTANCE;
public void sayHi() {
System.out.println("Hi");
}
}
这样当试图通过反射机制创建对象时,会抛出异常!