1.饿汉模式
//饿汉单例模式
//线程安全 调用效率高 不能延迟加载
public class SingletonHungry {
//私有化构造器---不能再外部生成该类的对象,只用通过指定的接口才能得到
private SingletonHungry() {
};
//提供静态成员变量,在类加载的时候初始化
private static SingletonHungry sh = new SingletonHungry();
//提供获取静态成员对象的方法
public static SingletonHungry getInstance() {
return sh;
}
}
2.懒汉模式
//懒汉模式
//线程安全 调用效率不高 可以延时加载
public class SingletonLazy {
//私有化构造方法
private SingletonLazy() {};
//声明静态成员
private static SingletonLazy sl;
//定义获得实例的方法
//添加synchronized关键字是为了保证线程安全--=对该方法进行加锁
public static synchronized SingletonLazy getInstance() {
if(sl==null) {//起到了延时加载的作用
sl = new SingletonLazy();
}
return sl;
}
/*
* 之所以加synchronized关键字是因为如果一个线程通过了if判断,
* 在实例化的之前,另一个线程也通过了if判断,那么就会生成
* 两个不同的对象,而synchronized就保证了这个方法是同步的,
* 在被线程占用的情况下,另一个线程是不能访问的
*/
/*
* 但是synchronized会很耗费cpu资源,其实只有第一次进行初始化
* 的时候才用加锁
*/
}
3.双重锁检测问题
//双重检测锁
public class SingletonDoubleLock {
//私有化构造方法
private SingletonDoubleLock() {};
//提供未初始化的静态成员
private volatile static SingletonDoubleLock sd = null;
//声明获得实例的方法
public static SingletonDoubleLock getInstance() {
if(null == sd) {
synchronized (SingletonDoubleLock.class) {
if(null == sd) {
sd = new SingletonDoubleLock();//problem
}
}
}
return sd;
}
/*
* 虽然上面的方法解决了cpu消耗大的问题,但是由于jvm底层内部
* 模型的原因,有一个隐患。
* 标记为problem的那行,实际在运行中可以分为三个步骤:
* 1.分配内存空间 2.初始化对象 3.将对象指向刚分配的内存空间
* 但是有些编译器为了性能之类的原因,可能将第二步和第三部重排序
* 就是jvm重排序问题,导致了问题。这时如果sd刚指向内存空间但是没有
* 初始化,那么sd不为空但是没有值,如果这个时候另一个线程访问该实例
* 不为空,但是没有值就会报错,这时就要在声明sd这个对象的时候
* 加上volatile关键字 将重排序禁止就好
*/
}
//参考文章:https://www.cnblogs.com/xz816111/p/8470048.html
// https://blog.csdn.net/betonme/article/details/86527654
4.静态内部类实现懒汉模式
//静态内部实现---属于懒汉模式
//线程安全 懒加载 只有真正调用getInstance才会加载静态内部类,线程安全
//static final 保证了内存中只有一个实例存在,而且只能被赋值一次
//爆炸了线程安全性 兼备了高并发和延迟加载的优势
public class SingletonStaticClass {
private SingletonStaticClass() {
System.out.println(System.currentTimeMillis());
};
private static class SingletonClassInstance{
private static final SingletonStaticClass instance = new SingletonStaticClass();
}
private static SingletonStaticClass getInstance() {
return SingletonClassInstance.instance;
}
}
以上四个代码段分别描述了四种实现单例模式的方法及其优缺点,希望对你有所帮助。如有描述错误的地方,请指出,后期会更正。