单例模式
什么时候用单例模式?
1. 对象中包含多种消耗资源的行为例如线程池,缓存,网络、数据库、IO等.
2. 整个系统中只需要拥有一个全局对象
定义?
1. 确保某一个类只有一个实例,并且自行实例化向整个系统提供整个实例
使用场景
1. 确保某个类有且只有一个对象的场景,避免多个对象消耗过多的资源,或者某种类型的对象应该有且只有一个
单例模式主要特点:
1. 构造函数不对外开放一般为private
2. 通过一个静态方法或者枚举返回单利类对象
3. 确保单例类的对象有且只有一个,尤其是在多线程环境下
4. 确保单例类对象在反序列化时候不会重新构建对象
代码示例
public class IetonA{ privateIetonA
ietonA;
private IetonA(){
}
public staticIetonA
getInstance(){
if
(ietonA==
null){
synchronized (IetonA.class){
if (ietonA==
null){
ietonA =new
IetonA();
}
}
}
return ietonA;
}
}
深入分析对象的创建ietonA = new IetonA()
1..给IetonA的实例分配内存
2.调用IetonA的构造函数,初始化成员字段
3.讲ietonA对象指向分配的内存空间(这个时候对象就不是null的了)
DCL优点:
资源利用率高,第一次执行getInstance时候单利对象才会被实例化
缺点:
第一次加载时候反应稍微慢了一点 高并发也有一定的缺陷,概率很小
静态内部类单利模式
private IetonA() {}
public static IetonA getInstance() {
return IetonAHolder.sInstance;}
private static class IetonAHolder {
private static final IetonA sInstance = new IetonA();
}
特点:
不仅能够保证线程的安全 而且还能保证单例对象的唯一性 同时也延迟了单利的实例化 推荐这种单利模式实现
枚举单例
private IetonA() {}
public enum IetonAEnum{
INSTANCE;
public void doSomething(){
}}
优点:
默认枚举实例的创建时线程安全的,并且在任何情况下他都是一个单例即使被反序列化他也不会重新生成新的实例
如何杜绝单例对象被反序列化时重新生成对象,那么必须加入
private Object readResolve() throws ObjectStreamException{
return ietonA;
}
使用容器实现单例模式
private static Map<String,Object> map = new HashMap<>();
public static void registerService(String key,Object instance){
if (!map.containsKey(key)){
map.put(key,instance);}}
public static Object getService(String key){
return map.get(key);}
通常情况下 客户端的并发不是很高 所以DCL和静态内部类单利就能够使用
单例模式
优点
1.单利模式在内存中只有一个,那么久节省了内存的开支,
2. 只生成一个实例,减少了系统的性能开销,当一个对象产生需要比较多的资源时候比如配置读取产生其他依赖对象时候们可以通过应用产生一个单例对象 然后永久的贮存内存的方式解决
3. 单利模式可以避免对资源的多重占用,例如一个写文件操作由于一个实例存在内存中,避免对同一个资源文件的同时写操作
4. 单利模式可以在系统设置全局的访问点,优化和共享资源访问,
缺点
1.单利模式一般没有接口。扩展很困难,若要扩展就需要修改代码
2.单利对象如果持有context容易引发内存泄漏,此时最好使用ApplicationContext