案例引入
在面向对象世界里,一切的行为都是通过对象实现,但是频繁创建销毁对象是非常耗时的,而且部分场景下是不允许的,设想一下,假如我们为每一次连接都创建一个数据库连接对象,数据库的仅仅是为了保持这些连接信息都会爆炸了,但实话实说,我们有必要保持那么多信息吗,比如数据库连接对象,我们并不需要太多的重复,我们只需要一个基本的数据库认证信息,我们把这些信息直接作为公有的部分,这跳出对象的层次,让需要的人都可以拿到一份,而无需重复创建,这样不就可以规避了重复创建对象的问题了吗。而这种做法被称为单例模式。
单例模式
实现方法
所谓单例模式是指将对象的实例化从直接创建转变成通过类的静态方法实例化,每次对象的获取只能通过静态方法进行获取,保证了一个类只有一个实例对象。
懒汉模式VS饿汉模式
单例模式的实现思路有两种,一种是懒汉模式,一种是饿汉模式,这两种代表了不同的实例化思路,第一种是延迟实例化,由程序决定实例化的时机,一种是类加载时候就进行实例化。两张各有优缺,懒汉模式可能导致线程安全性问题,饿汉模式又存在资源浪费问题,但是使用上,建议使用饿汉模式。
单例模式的应用例子
饿汉模式
类加载时候,直接对对象实例化,可以实现线程安全。
public class DBConnect {
private static DBConnect dbConnect =new DBConnect();
public static DBConnect getObject(){
return dbConnect;
}
}
懒汉模式
懒汉式
synchronized可以避免多线程下,线程安全问题,但效率最低
public class LazyDBConnect {
private static LazyDBConnect dbConnect =null;
public static synchronized LazyDBConnect getObject(){
if(dbConnect==null){
dbConnect = new LazyDBConnect();
}
return dbConnect;
}
}
DCL双检查
为了提高多线程性能,在jdk1.5之后推出了DCL双锁的方法,在多线程下仍然可以发挥出高效的性能。
public class DCLLazyDBConnect {
static volatile DCLLazyDBConnect dbConnect =null;
private DCLLazyDBConnect(){}
public static DCLLazyDBConnect getObject(){
if(dbConnect==null){
synchronized (DCLLazyDBConnect.class){
dbConnect = new DCLLazyDBConnect();
}
}
return dbConnect;
}
}
单例模式的优缺点
优点
确保所有对象只访问一个对象,系统对象访问控制更为简单
避免系统资源的浪费
可自由决定实例化对象的进程
缺点
不支持接口和继承,与设计模式的单一原则相冲突
案例
数据库连接池
程序的计数器
Spring的对象容器