单例模式是指确保一个类只有一个实例,并提供一个全局访问点。
单例模式的类图:
单例模式的几种实现方式及优缺点:
1、懒汉方式
public class Singleton1 {//懒汉模式
private static Singleton1 instance;
private Singleton1(){}
//线程安全的,如果去掉synchronized就是不安全的
public synchronized static Singleton1 getInstance(){
if(instance==null){
instance=new Singleton1();
}
return instance;
}
}
优缺点:
1、延迟加载:只是在第一次需要的时候才实例化对象,类加载比较快。
2、首次获取对象可能稍微的慢一点。
3、线程安全的懒汉模式效率很低,因为需要加锁,而其实大多数条件下是不需要加锁的。
2、饿汉模式
public class Singleton2 {//饿汉模式
private static Singleton2 instance=new Singleton2();
private Singleton2(){}
public static Singleton2 getInstance(){
return instance;
}
}
优缺点:
1、不需要加锁操作就可以实现线程安全,效率高。首次获取对象的速度也比较快。
2、不是延迟加载,在类加载的时候就实例化对象,导致类加载过程较慢。而且,如果从始至终从未使用过这个实例,则会造成内存的浪费。
3、静态内部类模式
public class Singleton3 {//静态内部类
private Singleton3(){}
private static class SingletonHolder{
private static Singleton3 instance=new Singleton3();
}
public static Singleton3 getInstance(){
return SingletonHolder.instance;
}
}
在加载Singleton3的时候并不会加载内部类,只有在调用getInstance()方法获取实例时才会加载内部类SingletonHolder,加载内部类的时候会实例化Singleton3。因此是延迟加载。类的静态属性只有在第一次加载的时候初始化,因此是线程安全的。
优点:线程安全且效率高、延迟加载
4、双重检验锁
public class Singleton4 {//双重检验锁
private volatile static Singleton4 instance;
private Singleton4(){}
public static Singleton4 getInstance(){
if(instance==null){
synchronized(Singleton4.class){
if(instance==null){
instance=new Singleton4();
}
}
}
return instance;
}
}
两次if判断可以保证线程安全,而且volatile也保证了instance的可见性。并且加锁只会执行一次(有可能两次),实例化之后不会再执行加锁操作了,因此效率比较高。
优点:延迟加载、线程安全、效率较高。
缺点:只有在JDK1.5之后才能正常执行。
单例模式的优缺点:
优点:
1、由于在系统内存中只存在一个对象,因此可以节约系统资源,当需要频繁创建和销毁对象时,单例模式无疑可以提高系统的性能。
2、提供了对唯一实例的受控访问。(确保了只有一个实例)
3、避免对共享资源的多重占用。
缺点:
1、不适用于变化的对象,如果同一类型的对象总是要在不同的使用场景发生变化,单例就会引起数据的错误,不能保存彼此的状态。
2、由于单利模式中没有抽象层,因此单例类的扩展有很大的困难。
3、单例模式在一定程度上违背了类的“单一职责原则”。因为其不仅要管理自己的实例,还要在应用程序中担当一个角色。
注意:多个不同的类加载器都会加载一次同一个类,因此在整个程序中,同一个类会被加载多次,这会破坏单例模式。
应用场景:
1、需要频繁实例化然后销毁的对象。
2、创建对象时耗时过多或者耗资源过多,但又经常用到的对象。
3、有状态的工具类对象。
应用示例:
1、Windows的任务管理器是典型的单例模式。
2、网站的计数器,一般也是采用单例模式实现,否则难以同步。
3、打印机的打印程序也要是单例的,否则可能会有两个打印作业同时传到打印机上。造成打印混乱。
发个女帝镇楼,女帝是独一无二的!哈哈哈