饿汉
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() { }
public static Singleton getInstance() {
return instance;
}
}
私有化构造函数,创建内部静态对象,通过静态方法返回。
或者如下,一个效果
public class Singleton {
private static Singleton instance = null;
static {
instance = new Singleton();
}
private Singleton() { }
public static Singleton getInstance() {
return this.instance;
}
}
缺点,没有按需求创建对象,导致资源浪费
懒汉
按需生成全局唯一对象
public class Singleton {
private static Singleton instance = null;
private Singleton() { }
public static Synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
缺点,Synchronized会导致每次访问,都需要加锁和释放锁,而实际下对象已经有了,何必还这么做,资源浪费。
双重校验
懒汉的变种,提高性能,按需生成对象,后续不需要加锁。
public class Singleton {
private static Singleton instance = null;
private Singleton() { }
public static Singleton getInstance() {
if (instance == null) { //如果已经初始化,不需要加锁了
synchronized(Singleton.class) { //未初始化时候会产生竞争,
if (instance == null) { //第二重校验,为了方式被唤醒的进程再次初始化
instance = new Singleton();
}
}
}
return instance;
}
}
以上代码,提升性能,但是会有指令重排的问题,指令重排,是JVM优化代码的过程,再不影响最终结果的时候,调整指令执行顺序,这样,会导致双重校验失效,改进,使用volatile
public class Singleton {
private static volatile Singleton instance = null;
private Singleton() { }
public static Singleton getInstance() {
if (instance == null) {
synchronized(Singleton.class) {
if (instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
静态内部类
public class StaticSingleton {
private StaticSingleton() {}
private static class SingletonHolder {
private static StaticSingleton INSTANCE = new StaticSingleton();
}
public static StaticSingleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
枚举
上述方法虽然可以通过私有化构造函数实现单列,但是通过反射机制,仍然可以强行构造新的对象,StaticSingleton tmp=(StaticSingleton)Class.forName("com.xx.StaticSingleton").newInstance();
因此,使用枚举,可以避免这个
- 枚举的构造函数必须是私有
- 枚举中的属性必须放在最前面,通常大写
- 枚举中可以定义方法,属性可以重写方法,引用方法
public enum TrafficLamp {
RED(30) {
//实现抽象方法
public TrafficLamp nextLamp() {
return GREEN;
}
},
GREEN(20) {
public TrafficLamp nextLamp() {
return YELLOW;
}
},
YELLOW(10) {
public TrafficLamp nextLamp() {
return RED;
}
};
//抽象方法
public abstract TrafficLamp nextLamp();
private int time;
private TrafficLamp(int time) {
this.time = time;
}
public static void main(String[] args) {
try {
TrafficLamp tmp=(TrafficLamp)Class.forName("com.roocon.thread.t5.TrafficLamp").newInstance();
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
这里面的,RED GREEN YELLOW 都是单例的,而且,对枚举进行反射会报错,
java.lang.InstantiationException: com.roocon.thread.t5.TrafficLamp
at java.lang.Class.newInstance(Class.java:427)
at com.roocon.thread.t5.TrafficLamp.main(TrafficLamp.java:30)
Caused by: java.lang.NoSuchMethodException: com.roocon.thread.t5.TrafficLamp.<init>()
at java.lang.Class.getConstructor0(Class.java:3082)
at java.lang.Class.newInstance(Class.java:412)
... 1 more
网友评论