什么是单例设计模式?
对于单例设计模式来说,其实和生活密不可分。假如说你的生活中有些东西只能有一个,比如亲人。任何时间你想找父亲开视频聊天,找到的都是唯一的一个父亲。不可能说两次通话找到的不同的父亲。例子可能不是很恰当。就是说这样一个需求,每次获取一个对象时,所拿到的对象都是同一个对象。
对单例来说其主要规则有如下三点:
1. 其构造器必须是private
的,不能通过new
来创建对象。
2. 只能通过唯一一个静态函数来获取对象
3. 因为只能通过静态函数来获取对象,所以其对象也必须是静态且私有的。
对于单例设计模式,其实现方式有两种:
- 饿汉式单例,程序启动时就创建一个唯一的实例对象,即单例类定义的时候就进行实例化
- 懒汉式单例,当第一次使用时才创建一个唯一的实例对象,从而实现延迟加载的效果
饿汉式单例
public class Singleton
{
//1.私有化构造器
private Singleton()
{
}
//2.内部创建私有静态对象
private static Singleton instance=new Singleton();
//3.提供公共的静态方法
public static Singleton getInstance()
{
return instance;
}
}
懒汉式单例
public class Singleton
{
//1.私有化构造器
private Singleton()
{
}
//2.内部声明私有静态对象为null
private static Singleton instance=null;
//3.提供公共的静态方法,判断instance是否存在,不存在再创建
public static Singleton getInstance()
{
if(instance==null)
{
instance=new Singleton();
}
return instance;
}
}
饿汉和懒汉的区别
- 饿汉,一开始就创建对象,可能还没用到,加载的时间过长,其生命周期太长。
其天然线程安全
。 - 懒汉,延迟加载,等到用的时候才创建,节省内存。但是需要自己实现其线程安全。
线程安全的懒汉式单例
首先分析目前出现的线程不安全状况
public static Singleton getInstance()
{
if(instance==null) //当第一个线程创建单例式,访问到这一步,条件满足,准备去new
{ //另外一个线程也访问到这一步,第一个线程还没访问new,条件也满足,这个线程也去new。
instance=new Singleton(); //结果两个线程各自new了一次。打破了单例
}
return instance;
}
对此我们可以对临界区加锁来保证线程安全,这里写的是效率较高的双重检验锁。如下:
public class Singleton
{
//1.私有化构造器
private Singleton()
{
}
//2.内部声明私有静态对象为null
private static Singleton instance=null;
//3.提供公共的静态方法,判断instance是否存在,不存在再创建
public static Singleton getInstance()
{
//4、多线程条件下,为了提高效率,要双重校验,先判断是否为null。第一个线程访问创建完毕后,后续线程先判断,再考虑加锁,这样就不用乱加锁浪费性能
if(instance==null)
{
//5、加锁保证线程同步,此时synchronized的加锁对象是Singleton这个类对象
synchronized(Singleton.class)
{
//6、一开始访问的时候,才有线程能访问到这里,进而new对象
if(instance==null)
{
instance=new Singleton();
}
}
}
return instance;
}
}
单例的适用场景
拿我们的windows电脑来说,我们平常适用微信的时候,即使双击两次,访问的还是同一个微信程序。
还有比如任务管理器等等。