关于ThreadLocal?

在每一个线程Thread对象中,都维护了一个ThreadLocalMap对象,ThreadLocal的生命周期和线程相同。
ThreadLocalMap中又维护了一个k v 形式的Entry对象,key指向了当前ThreadLocal对象,value就是在ThreadLocal中存储的值。this.threadLocalName.set(要存的值),this.get(threadLocalName)。

为什么会出现内存泄露?
正常来说,ThreadLocal会随线程结束而销毁,然而在线程池等场景下线程会一直复用。
在Entry中的key存储的是ThreadLocal的弱引用。
所以,在当前线程正在运行的时候,发生GC时,在ThreadLocal对象没有被其它地方强引用时,key指向ThreadLocal的虚引用就会立即断开(被垃圾回收掉),这时,就会出现ThreadLocalMap中存在key为null的Entry,只要当前线程不结束,该ThreadLocalMap对象就会一直存在,永远无法回收。

Entry对象的key为什么要使用弱引用,有什么好处?
其实,ThreadLocalMap在设计时就考虑到了内存泄露,它也采取了一些措施来避免这种key为null,而value不为null的对象占用内存,在我们调用ThreadLocal的set、get、remove方法时,都会将这些key为null的对象清空掉,避免因为这种情况而导致内存泄露。
假设如果存储的强引用,我们断开ThreadLocal Reference —> ThreadLocal的引用,会发现key强引用了ThreadLocal,导致该对象永远无法被GC。

并发三大特性

原子性,可见性,有序性。

i++为何不是原子性操作?

先从主存读数据,+1操作,写到缓存,刷到主存。volatile保证可见性和有序性,sycronized保证有序性。autointiger采用volatile+CAW实现原子操作。

volatile 关键字,他是如何保证可见性,有序性?

  1. 对于加了 volatile 关键字的成员变量,在对这个变量进行修改时,会直接将 CPU 高级缓存中的数据写回到主内存,对这个变量的读取也会直接从主内存中读取,从而保证了可见性。
  2. 在对 volatile 修饰的成员变量进行读写时,会插入内存屏障,而内存屏障可以达到禁止重排序的效果,从而可以保证有序性

Bean的创建过程

Spring框架中Bean的创建过程是怎样的?
首先,简单来说,Spring框架中的Bean经过四个阶段:实例化—》属性赋值—》初始化—》销毁然后:具体来说,Spring中Bean经过了以下几个步骤:
1、实例化:new xxx();两个时机:1、当客户端向容器申请一个Bean时,2、当容器在初始化一个Bean时发现还需要依赖另一个Bean。BeanDefinition 对象保存。—到底是new一个对象还是创建一个动态代理?
2、设置对象属性(依赖注入):Spring通过BeanDefinition找到对象依赖的其他对象,并将这些对象赋予当前对象。

3、处理Aware接口:Spring会检测对象是否实现了xxxAware接口,如果实现了,就会调用对应的方法。
BeanNameAware、BeanClassLoaderAware、BeanFactoryAware、ApplicationContextAware

4、BeanPostProcessor前置处理:调用BeanPostProcessor的postProcessBeforelnitialization方法
5、InitializingBean:Spring检测对象如果实现了这个接口,就会执行他的afterPropertiesSet()方法,定制初始化逻辑。 6、init-method: <bean init-method=xxx>如果Spring发现Bean配置了这个属性,就会调用他的配置方法,执行初 始化逻辑。即使用@PostConstruct注解。
7、BeanPostProcessor后置处理:调用BeanPostProcessor的postProcessAfterlnitialization方法
到这里,这个Bean的创建过程就完成了,Bean就可以正常使用了。
8 、销毁

抽象类和接口

  1. 抽象类中的方法不必被重写: 抽象类可以包含抽象方法(没有方法体)和具体方法(有方法体)。子类继承抽象类时,可以选择性地覆盖(重写)抽象方法,但不强制要求覆盖所有抽象方法。如果子类不覆盖抽象方法,那么该子类也必须被声明为抽象类。具体方法可以被子类继承而不需要覆盖。抽象类的主要目的是为了提供一些通用的实现,同时留下一些方法供子类实现或覆盖。
  2. 接口中的方法必须被实现: 接口中的方法都是抽象的,只包含方法的声明,没有方法体。当一个类实现一个接口时,它必须提供实现接口中所有方法的具体实现。否则,该类必须被声明为抽象类。因此,接口的方法对实现类来说是强制性的,必须被实现。