属于创建型模式
定义
确保一个类在任何情况下都绝对只有一个实例,并提供一个全局访问点。
一山不容二虎。
2.适用场景
ServletContext、 ServletConfig、ApplicationContextDBPool。
3.常见写法
饿汉式单例、懒汉式单例、注册式单例、ThreadLocal式。
饿汉式写法
public class HungryStaticSington {
private static final HungryStaticSington hungryStaticSington = new HungryStaticSington();
public HungryStaticSington getHungryStaticSington(){
return hungryStaticSington;
}
private HungryStaticSington(){}
}
/类的加载顺序
//先静态后动态
//先上后下
//先属性后方法
public class HungryStaticSington2 {
private static final HungryStaticSington2 hungryStaticSington;
static {
hungryStaticSington = new HungryStaticSington2();
}
public HungryStaticSington2 getHungryStaticSington(){
return hungryStaticSington;
}
private HungryStaticSington2(){}
}
以上两种方法类似本质相同。
优点:执行效率高、性能高、没有任何锁。
缺点:某些情况下,可能会造成内存浪费。
懒汉式单例:
在加载时再创建。
public class LazySington {
public static LazySington lazySington;
public static LazySington getInstance(){
if (lazySington == null){
lazySington = new LazySington();
return lazySington;
}
return lazySington;
}
private LazySington(){
}
}
此方法创建出来的单例会有一下几种情况
图一:
图二:
图一是 两个线程都进入了if(lazySington == nul) new了个对象并打印出来了
图二是 两种情况第一种第一个线程进入了if(lazySington == nul)中new了一个对象并赋值 与此同时第二个线程也进入了if(lazySington == nul)中new了对象并且把前一个线程的值改了,所以结果是两个一样的对象。
图二的第二种情况是按照正常的咱们设计这个单例的思想来进行的得到的相同的结果。
所以咋办呢?
咱们加锁改良啊。。就有了以下代码!!
运行多次,结果都一致。
符合了预期,但是缺点是什么呢就是性能不好,阻塞太严重!!
那就改!!
改成这样 然并卵。。运行结果如下:
再改!!
改成这样 ,成功了,这就是双重检查