一、什么是单例模式
在整个系统中,一个类型只有一个实例,对JAVA来说:一个类只能被实例化一次
一、什么时候使用单例模式
1.单例模式可以控制资源达到节约资源的目的
2.单例模式可以做多线程之间的通信
基于以上两点:可以想到平时用的数据库连接池,线程池都常采用单例模式
三、如何实现单例模式(JAVA)
普通类:私有静态成员变量、私有构造函数、公有返回实例函数
枚举类:天生特性就满足单例模式
1.懒汉模式
public class CarToolLazy implements CarTool{
private static final CarTool ct ;
private CarToolLazy(){}
public static CarTool getInstance(){
if(ct==null){
ct = new CarToolLazy();
}
return ct;
}
}
优点:需要对象时,才会被实例化
缺点:存在线程安全问题,线程1在if(ct==null)执行完时,失去CPU资源,线程2得到CPU资源实例化了对象,线程1得到资源,也实例化了对象,此时就存在多个对象,违反了单例模式的原则
2.饿汉模式
public class CarToolHungry implements CarTool{
private static final CarTool ct = new CarToolHungry();
private CarToolHungry(){}
public static CarTool getInstance(){
return ct;
}
}
优点:线程安全
缺点:因为在类加载的时候就实例化了对象,如果此对象很少用、根本没用、很晚才用、那对资源是一种浪费,且会增加类加载的时长(如果实例化这个对象需要做很多消耗资源或者等待资源的时候)
注:类加载动作是原子的,不能被打断
3.懒汉模式变种
public class CarToolLazyNew implements CarTool{
private static class singleTonUtil{
public static final CarTool ct= new CarToolLazyNew();
}
private CarToolLazyNew(){}
public static CarTool getInstance(){
return singleTonUtil.ct;
}
}
优点:线程安全,在对象需要时实例化
缺点:无
注:此方式利用了静态内部类实现,类加载时不会去实例化内部类的成员变量,只有当调用getInstance()方法时才会实例化对象。
4.饿汉模式变种
public class CarToolHungryNew implements CarTool{
private static final CarTool ct ;
static{
ct = new CarToolHungryNew();
}
private CarToolHungryNew(){}
public static CarTool getInstance(){
return ct;
}
}
优点:线程安全
缺点:因为在类加载的时候就实例化了对象,如果此对象很少用、根本没用、很晚才用、那对资源是一种浪费,且会增加类加载的时长(如果实例化这个对象需要做很多消耗资源或者等待资源的时候)
注:这种实现方式和饿汉模式没有本质区别,只是把对象的初始化放在了静态代码块中。依然是利用类加载动作是原子的,不能被打断特性,做到线程安全
5.双重检查
public class CarToolSynDouble implements CarTool{
//如果不用volatile变量会导致实例化之后,另外的线程并不能看见实例化
private volatile static CarTool ct ;
private CarToolSynDouble(){}
public static CarTool getInstance(){
if(ct==null){
synchronized (CarToolSynDouble.class) {
if(ct==null){
ct = new CarToolSynDouble();
}
}
}
return ct;
}
}
优点:线程安全,需要时实例化对象
缺点:代码复杂
注:利用双重if(ct==null)判断,加同步原语,加volatile变量实现线程安全,至于为什么使用volatile变量,可以对volatile关键字做深入了解,本质原因就是JAVA内存模型中线程私有内存与主内存的同步知识点,有的同学在使用双重检查的时候没有加volatile修饰,则依然会出现多个实例的情况。
6.使用同步方法
public class CarToolSyn implements CarTool{
private static CarTool ct ;
private CarToolSyn(){}
public static synchronized CarTool getInstance(){
if(ct==null){
ct = new CarToolSyn();
}
return ct;
}
}
优点:线程安全
缺点:锁资源竞争严重,效率低
7.使用枚举类
public enum CarToolEnum {
instance;
private CarTool ctie;
private CarToolEnum(){
ctie = new CarToolImplEnum();
}
public CarTool getInstance(){
return ctie;
}
}
class CarToolImplEnum implements CarTool{}
优点:线程安全,为了线程安全不用写额外代码做控制
缺点:无
注:利用枚举类型实例本身就是唯一的特性,简单实现单例模式