单例模式的要点
(1)某个类只能有一个实例
(2)它必须自行创建这个实例
(3)它必须向整个系统提供这个实例
1. 饿汉式
在类加载时已经创建好该对象,在程序调用时直接返回该对象实例。
public class Single1 {
//私有构造方法(除了反射都不能new对象)
private Single1() {
}
//私有的声明对象属性(自己在自己的类中new好了)
//类加载时对象被加载
private static Single1 instance = new Single1();
//公共(向整个系统提供) 只能通过这个方法调用
public static Single1 getInstance() {
return instance;
}
}
2.懒汉式
在真正需要该对象时才去创建该单例对象
public class Single2 {
//私有构造方法
private Single2() {
}
private static Single2 instance;//null
public static Single2 getInstance() {
if (instance == null) {
instance = new Single2();
}
return instance;
}
}
3.双重校验
如果两个线程同时判断是否为空,那麽两个都会实例化一个对象,就变成双例了,所以为了解决线程不安全问题,我们给方法上加锁。
public class Single3 {
//构造器私有
private Single3() {
}
//声明属性私有
private static Single3 instance;
//双重校验机制(线程不安全)
public static Single3 getInstance() {
synchronized (Object.class) {
if (instance == null) {
instance = new Single3();
}
}
return instance;
}
}
这个代码还会出现问题,每次获取对象都会先加锁,并发性能差,所以进行优化代码。
public class Single3 {
//构造器私有
private Single3() {
}
//声明属性私有
private static Single3 instance;
//双重校验机制(线程不安全)
public static Single3 getInstance() {
//提高代码的效率
if (instance == null) {
//加锁
synchronized (Object.class) {
if (instance == null) {
instance = new Single3();
}
}
}
return instance;
}
}
4.静态内部类
public class Single4 {
//私有构造方法
private Single4() {
}
private static class Inner {
//finial可加可不加
private final static Single4 instance = new Single4();
}
public static Single4 getInstance() {
//只有实际调用了这个方法,instanse才会产生
return Inner.instance;
}
}
静态内部类优点:外部类在加载时并不需要立即加载内部类,内部类不被加载就不会初始化instance,所以不占内存。这种方法不仅能够保证线程安全,也能保证单例的唯一性,同时也延迟了单例的实例化。
5.枚举
public enum Single5 {
INSTANCE;
public Single5 getInstance() {
return INSTANCE;
}
}
枚举的优点:代码精简,没有线程安全问题,并且在enum类中有防止反射和反序列化时破坏单例。