什么是单例?
单例就是在程序中,单例对象只有一个实例
饿汉式
/**
* 饿汉式
* 类加载到内存之后,就实例化一个单例,JVM保证线程安全
* 简单实用,推荐使用
* 唯一缺点:不管这个对象用到还是没有用到,类加载时就完成实例化
*/
public class Demo02_hungry {
private static volatile Demo02_hungry demo02_hungry = new Demo02_hungry();
private Demo02_hungry(){}
public static Demo02_hungry getInstance(){
return demo02_hungry;
}
public static void main(String[] args) {
Demo02_hungry instance = Demo02_hungry.getInstance();
Demo02_hungry instance1 = Demo02_hungry.getInstance();
System.out.println(instance==instance1);
}
}
懒汉式
饿汉式有一个缺点,就是不管用不用他,类加载的时候都会去实例化一个对象,如果想解决这个缺点,就可以用懒汉式。
/**
* 懒汉式 什么时候用,什么时候实例化
*/
public class Demo01_lazy {
private static Demo01_lazy demo01_lazy;
private Demo01_lazy(){}
public static Demo01_lazy getInstance() throws InterruptedException {
if(demo01_lazy==null){
demo01_lazy = new Demo01_lazy();
}
return demo01_lazy;
}
}
这样写如果在高并发的情况下是会存在线程不安全的问题。我们就需要加锁来对他保证线程安全。
/**
* 懒汉式 什么时候用,什么时候实例化
*/
public class Demo01_lazy {
private static Demo01_lazy demo01_lazy;
private Demo01_lazy(){}
public static Demo01_lazy getInstance() throws InterruptedException {
synchronized (Demo01_lazy.class){
if(demo01_lazy==null){
demo01_lazy = new Demo01_lazy();
}
}
return demo01_lazy;
}
}
那现在我们在来思考一个问题,加了synchronized锁之后,那是不是我每次调用getInstance()方法,都需要通过锁,效率是不是就低了呢,如果想解决这个问题该怎么办呢?看以下代码。
/**
* 懒汉式 什么时候用,什么时候实例化
*/
public class Demo01_lazy {
private static Demo01_lazy demo01_lazy;
private Demo01_lazy(){}
public static Demo01_lazy getInstance() throws InterruptedException {
if(demo01_lazy == null){
synchronized (Demo01_lazy.class){
if(demo01_lazy==null){
demo01_lazy = new Demo01_lazy();
}
}
}
return demo01_lazy;
}
}
我们可以在锁上面再加个判断,判断实例是否为空,如果不为空直接返回,如果为空,再走synchronized代码块,这也就是我们常说的双重校验。