疏漏总结(三)

  1. SpringIOC内部是如何避免循环引用Bean的
public class BeanB {
    private BeanA beanA;
}

public class BeanA {
    private BeanB beanB;
}

假如有上面的场景,我们发现有一种循环引用的情况,正在加载的时候,我们会循环产生实例,这样就会oom了,但是IOC内部的一种操作避免了这种情况的发生。

在容器再次发现 beanB 依赖于 beanA 时,容器会获取 beanA 对象的一个早期的引用(early reference),并把这个早期引用注入到 beanB 中,让 beanB 先完成实例化。beanB 完成实例化,beanA 就可以获取到 beanB 的引用,beanA 随之完成实例化。

从源码来分析的话:
①首先创建原始的本地bean的对象

instanceWrapper = createBeanInstance(beanName, mbd, args);
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);

②暴露早期应用
将指向原始对象的引用通过ObjectFactory 暴露出去,里面getEarlyBeanReference的第三个参数bean就是这个对象

addSingletonFactory(beanName, new ObjectFactory<Object>() {
    @Override
    public Object getObject() throws BeansException {
        return getEarlyBeanReference(beanName, mbd, bean);
    }
});

③解析依赖
populateBean 用于向 beanA 这个原始对象中填充属性,当它检测到 beanA 依赖于 beanB 时,会首先去实例化 beanB。beanB 在此方法处也会解析自己的依赖,当它检测到 beanA 这个依赖,于是调用 BeanFactry.getBean(“beanA”) 这个方法,从容器中获取 beanA。

populateBean(beanName, mbd, instanceWrapper);

④获取早期引用
populateBean 调用 BeanFactry.getBean(“beanA”) 以获取 beanB 的依赖。

getBean(“beanA”) 会先调用 getSingleton(“beanA”),尝试从缓存中获取 beanA。

此时由于 beanA 还没完全实例化好,于是 this.singletonObjects.get(“beanA”) 返回 null。

接着 this.earlySingletonObjects.get(“beanA”) 也返回空,因为 beanA 早期引用还没放入到这个缓存中。

最后调用 singletonFactory.getObject() 返回 singletonObject,此时 singletonObject != null。

singletonObject 指向 BeanA@1234,也就是 createBeanInstance 创建的原始对象。

此时 beanB 获取到了这个原始对象的引用,beanB 就能顺利完成实例化。

beanB 完成实例化后,beanA 就能获取到 beanB 所指向的实例,beanA 随之也完成了实例化工作。

由于 beanB.beanA 和 beanA 指向的是同一个对象 BeanA@1234,所以 beanB 中的 beanA 此时也处于可用状态了。

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        synchronized (this.singletonObjects) {
            // ☆ 从缓存中获取早期引用
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    // ☆ 从 SingletonFactory 中获取早期引用
                    singletonObject = singletonFactory.getObject();
                    
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return (singletonObject != NULL_OBJECT ? singletonObject : null);
}

参考自:https://segmentfault.com/a/1190000015221968#item-4

  1. ReentrantLock的疏漏

默认是非公平锁,但是也可以通过构造函数转换成公平锁。

  1. 如何优雅的去中断一个线程。

方法一:可以使用interrupt方法,当其他线程通过调用当前线程的 interrupt 方法,表示向当前线程打个招呼,告诉他可以中断线程的执行了,至于什么时候中断,取决于当前线程自己。

方法二:定义一个volatile 修饰的成员变量,来控制线程的终止。这实际上是应用了volatile 能够实现多线程之间共享变量的可见性这一特点来实现的。

  1. final和线程安全之间的联系

首先我们知道java内部是拥有四层内存屏障的:Loadstore StoreLoad LoadLoad StoreStore。
其实这四种屏障倒是简单,Load就是读已完成,Store就是写可见。

在volatile中的设计是:
在每个volatile写操作前插入StoreStore屏障,在写操作后插入StoreLoad屏障;
在每个volatile读操作前插入LoadLoad屏障,在读操作后插入LoadStore屏障;

在final中的设计是:
写final域:在编译器写final域完毕,构造体结束之前,会插入一个StoreStore屏障,保证前面的对final写入对其他线程/CPU可见,并阻止重排序。
读final域:在上述规则2中,两步操作不能重排序的机理就是在读final域前插入了LoadLoad屏障。

  1. 介绍一下ThreadLocal如何避免发生oom

可以将ThreadLocalMap的key声明为强引用,或者让他保证自动remove

  1. 索引针对b+ 和哈希索引之间的选择

哈希索引好就好在不用大量查找索引再寻址,是一一对应关系,但是要求是没有大量重复键值缺点是不支持范围查询,不支持索引完成排序,不支持联合索引的最左前缀匹配规则。

InnoDB引擎默认使用b+,但是内部也可以使用自适应哈希索引缓冲区使用哈希索引。

  1. 为什么建立了索引,还有可能会走全表扫描

使用了in,not in,<>,IS NULL 或IS NOT NULL,> 及 < 操作符,like,union,

  1. redis突然接入了一个从节点,应该如何保证主从一致性

以redis2.8位分割,如果突然接入一个节点,那么在2.8之前会发送一个sync进行全量复制,2.8之后会发送一个psync进行部分复制或者全量复制。

  1. Tcp第三次握手如果握手失败了,会怎么办

服务端会等待超时重传,再次发送第二次握手,有一定的次数,一般的5次,那么服务端会转入一个失败的状态

  1. https是怎么做到更加安全的

https协议需要到CA申请证书,一般免费证书很少,需要交费。
http是超文本传输协议,信息是明文传输;https 则是具有安全性的ssl加密传输协议。
http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值