序言
今天呢,来说一下设计模式吧,一个强大且高效的设计模式,可以大大提高代码的可读性,保证我们代码的可靠性也会提高程序的效率,毫无疑问使用设计模式来优化程序十分重要,但我们光会用可不行,一定要知其然知其所以然,这样才能学习到其中的核心思想,今天说一下设计模式中的单例模式吧!
单例模式
单例模式:顾名思义,使用单例模式会保证我们的类只有一个实例。
设计步骤
保证类只有一个实例
- 构造函数私有化
- 对外提供一个获取实例的方法
单机模式下的单例:懒汉式
class Singleton {
private static volatile Singleton singleton=null;
//私有化构造函数
private Singleton(){
}
//懒汉式
public static Singleton getSingleton(){
if (singleton==null) {
singleton = new Singleton();
}
return singleton;
}
}
可以看出以上就是单机模式下的单例了
出现的问题
在并发访问情况下是有问题的,当singletonnull,当多个线程走到(singletonnull) 这里时,都会进入if代码块中进而会创建出多个实例
解决方法
可以采用双重检测机制来解决以上情况
懒汉式->优化
class Singleton {
private static volatile Singleton singleton=null;
private Singleton(){
}
//懒汉式
public static Singleton getSingleton(){
//双重检测机制:在并发场景下确保实例的唯一性
if (singleton==null){
synchronized (Singleton.class) {
if (singleton==null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
第一个if判断作用:提高效率,当已经singleton!=null时直接返回实例即可
synchronized来保证多线程环境下同一时间只有一个线程执行以下代码块
第二个if判断作用:在锁被释放,新的线程争抢到锁后判断一下当前是否已经存在实例
懒汉式->终极优化
大家觉得现在这个类是单例的吗?
其实它还不是完全单例的,还可以通过反射,序列化,克隆的方式创建出新的实例!那么我们就针对这些问题再做进一步的优化。
class Singleton implements Serializable,Cloneable {
static final long serialVersionUID=45L;
private static volatile Singleton singleton=null;
private static boolean isFristCreate = true;//默认是第一次创建(防止反射获取)
private Singleton(){
//防止反射破坏单例
if (isFristCreate){
//防止并发情况下多个反射同时获取
synchronized (Singleton.class){
if (isFristCreate) {
isFristCreate = false;
}else {
throw new RuntimeException("阻止通过反射来获取多个实例");
}
}
}else {
throw new RuntimeException("阻止通过反射来获取多个实例");
}
}
//懒汉式
public static Singleton getSingleton(){
//双重检测机制:在并发场景下确保实例的唯一性
if (singleton==null){
synchronized (Singleton.class) {
if (singleton==null) {
singleton = new Singleton();
}
}
}
return singleton;
}
//防止序列化破坏单例,序列化时会直接调用该方法,保证单例
Object readResolve() throws ObjectStreamException {
return singleton;
}
//防止克隆破坏单例
protected Singleton clone() throws CloneNotSupportedException {
return singleton;
}
}
以上就是单例模式——懒汉式的完全体了!
枚举形式
enum Singleton{
GO()
}
枚举天生就可以保证单例,且枚举方式可以防止反射,克隆,序列化破坏单例。
饿汉式
class Singleton {
private static volatile Singleton singleton=new Singleton();
//私有化构造函数
private Singleton(){
}
//懒汉式
public static Singleton getSingleton(){
return singleton;
}
}
这种方式在类加载阶段就会创建出实例
静态内部类
class StaticSingleton implements Serializable {
private static class InnerSingleton{
private static final StaticSingleton staticSingleton=new StaticSingleton();
}
private StaticSingleton(){
}
public static StaticSingleton get(){
return InnerSingleton.staticSingleton;
}
}
在保证了单例的前提下,只有调用内部类的属性时才会初始化,节省了空间
总结
以上就是创建单例模式的几种方法了,大家掌握了几种呢。