单例设计模式
单例设计模式是JAVA设计模式的其中之一,它也是在开发中用到最多的设计模式之一。为什么要用这个单例设计模式呢?其实主要是为了避免创建多个实例造成资源浪费,从它的名称我们也可以容易理解一点,“单例”指的是在一个类中,该类在他自己里面new(创建)单个对象,并且确保只有单个对象被创建,该类还向外提供了一种访问其唯一的对象的方式,不需要实例化该类对象,即可直接访问,在一些常用的工具类、线程池、缓存,数据库,账户登录系统、配置文件等程序中可能只允许我们创建一个对象,一方面如果创建多个对象可能引起程序的错误,另一方面创建多个对象也造成资源的浪费。
那什么是实例化呢?具体可以点击查看实例化
简单来说,单例设计模式就是用来保证应用中有且只有一个实例来使资源和内存得到充分利用的目的。
那么说明了几点:
(1) 单例类只能有一个实例。
(2) 单例类必须自己创建自己的唯一实例。
(3) 单例类必须给所有其他对象提供这一实例。
问题来了,怎么才能保证它有且只有一个实例呢?
- 不能让其他程序
new
对象 - 在该类中
new
一个对象,而不是能让其他程序new
出对象 - 给外部提供一个静态方法获取对象实例
单例设计模式的几种写法
(1) 饿汉式
(2) 懒汉式
饿汉式写法
描述:这种方式比较常用,但容易产生垃圾对象。
优点:没有加锁,执行效率会提高。
缺点:类加载时就初始化,浪费内存。
它基于 classloader
机制避免了多线程的同步问题,不过,instance
在类装载时就实例化,虽然导致类装载的原因有很多种,在单例模式中大多数都是调用 getInstance
方法, 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化 instance 显然没有达到 lazy loading 的效果
public class Singleton{
private static Singleton instance=new Singleton(); //在单例类中new一个对象
private Singleton(){}; //默认保留构造方法
public static Singleton getInstance(){
return instance;
}
}
可以通过下面这个静态方法来获取实例
Singleton instance = Singleton.getInstance();
小结:这种方法一旦加载就实例化了,没有任何停留,就算是没用到也会进行实例化,说明了会造成一定的内存消耗,但无关紧要,还是挺好的一种单例设计模式。
懒汉式写法(一)
描述:这种方式是最基本的实现方式,这种实现最大的问题就是不支持多线程。因为没有加锁 synchronized
,所以严格意义上它并不算单例模式。
这种方式 lazy loading 很明显,不要求线程安全,在多线程不能正常工作。
public class Singleton{
private static Singleton instance=null;
private Singleton(){}; //默认保留构造方法
public static Singleton getInstance(){
if(instance==null){
instance=new Singleton();
}
return instance;
}
}
这种懒汉式写法是不安全的写法:具体来说就是在多线程中,第一个线程通过if(instance = = null)
这个语句,而没能通过instance=new Singleton();
时,第二个线程也有可能进入了if(instance==null)
,这样的话就会造成实例化了两个对象,所以这个懒汉式存在线程安全问题。
懒汉式写法(二)
描述:这种方式具备很好的 lazy loading,能够在多线程中很好的工作,但是,效率很低,99% 情况下不需要同步。
优点:第一次调用才初始化,避免内存浪费。
缺点:必须加锁 synchronized
才能保证单例,但加锁会影响效率。
getInstance()
的性能对应用程序不是很关键(该方法使用不太频繁)。
但是可以通过修改达到线程安全的目的
public class Singleton{
private static Singleton instance=null;
private Singleton(){}; //默认保留构造方法
public static Singleton getInstance(){
if(instance==null){
synchronizeed(Singleton.class){
if(instance==null){
instance=new Singleton();
}
}
}
return instance;
}
}
这个是运用了双重校验锁,安全且在多线程情况下能保持高性能。
最后来个总结:
单例设计模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
1、构造方法私有化,
2、声明一个本类对象
3、给外部提供一个静态方法获取对象实例
两种实现方式:
1、饿汉式
2、懒汉式