这篇博客我想表达表达最近学的23中设计模型中的单例模式!
什么是单例模式?
单例模式是指在内存中创建且仅仅创建一次对象的设计模式,让我们想想如果在一个程序中我们总是使用一个对象而且作用都相同时,每次使用这个对象就要创建一个实例,而频繁的创建实例会使得内存一直在增加,而单例模式就可以在程序中创建一个对象,并且让需要调用的都共享这一个对象。
单例模式的类型及如何创建
单例模式有两种类型分为懒汉模式和饿汉模式
懒汉模式是指什么时候要用到才创建实例。
饿汉模式是在类加载的时候就创建好实例,等着程序使用。
懒汉模式和饿汉模式可以简单的理解为两种洗碗的模式
懒汉模式是吃完饭先不洗碗,等到什么时候要用到再洗。
饿汉模式则是吃完饭直接把碗洗了,等到下次吃饭就可以直接拿来用了。
懒汉模式创建单例对象
先上代码
public class Singleton {
public static Singleton singleton;
public Singleton(){
}
public static Singleton getSingleton(){
if(singleton==null){
singleton = new Singleton();
}
return singleton;
}
}
这个代码就是一个懒汉模式的单例模式,在需要调用的时候才创建对象,但是这里有一个问题,如果两个线程同时进行判断
if(singleton==null)
这个操作,那么就会导致创建了两个实例的这个情况,这显然不符合我们的单例的目的,对这就是之前说过的线程安全的问题,那么如何解决这个问题呢?
加锁!
public class Singleton {
public static Singleton singleton;
public Singleton(){
}
public static Singleton getSingleton(){
if(singleton==null){//在这里线程1和线程2同时进行判空的操作
synchronized (Singleton.class){//而这步加锁只能让一个线程进入
if(singleton==null){//一个线程进入了另一个线程无法进入
singleton = new Singleton();
}
}
}
return singleton;
}
}
我们可以将代码进行这样的优化,因为进行了两次判空并且对类对象进行了加锁
因此懒汉模式也被叫作:Double Check + Lock。
我们还可以将singleton这个变量进行volatile关键字的修饰保证他的内存可见性,使得每次线程读取的那个值是从内存当中读取,还可以解决指令重排序问题保证程序编码的顺序正常进行,而不是被编译器优化。
public class Singleton {
public static volatile Singleton singleton;
public Singleton(){
}
public static Singleton getSingleton(){
if(singleton==null){
synchronized (Singleton.class){
if(singleton==null){
singleton = new Singleton();
}
}
}
return singleton;
}
}
这样就是一个完美的懒汉模式的单例模式了。
饿汉模式创建单例对象
先让我们看看代码
public class Singleton {
public static final Singleton singleton = new Singleton();
public Singleton(){
}
public static Singleton getSingleton(){
return singleton;
}
}
饿汉模式很朴实无华,就是在类加载的时候就创建好实例,接着什么时候要用直接返回就好了。