Java基础10——ThreadLocal、动态代理

117 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

ThreadLocal

ThreadLocal可以放置线程级别的变量,使每个线程拥有自己的变量副本,修改不会影响其他线程

  • ThreadLoacl 有一个静态内部类 ThreadLocalMap,其 Key 是ThreadLocal 对象value是 Entry 对象ThreadLocalMap对象是每个线程私有的threadlocal容器。

  • 存在的问题

    1. 对于线程池,由于线程池会重用 Thread 对象ThreadLocal 也会被重用,造成一系列问题。
  1. 内存泄漏,由于 ThreadLocal 是弱引用但 Entry 的 value 是强引用,因此当 ThreadLocal 被垃圾回收后,value 依旧不会被释放,产生内存泄漏。(手动remove

img

ThreadLocal 内存泄漏的原因:

从上图中可以看出,ThreadLocalMap使用ThreadLocal的弱引用作为key,如果一个ThreadLocal不存在外部强引用时,Key(ThreadLocal)势必会被GC回收,这样就会导致静态的ThreadLocalMap中key为null, 而value还存在着强引用,只有thead线程退出或再次使用ThreadLocalMap时,value的强引用链条才会断掉。

为什么使用弱引用

弱引用的ThreadLocal不会内存泄漏,因为即使没有手动删除,ThreadLocal也会被回收。当key为null,在下一次ThreadLocalMap调用set(),get(),remove() 方法的时候会清除value值

总结:由于ThreadLocalMap是静态的,ThreadLocalMap与Thread生命周期一样长,静态的ThreadLocalMap中key为null, 而value还存在着强引用,如果没有手动删除对应key,会导致内存泄漏。

动态代理

JDK动态代理

  • 使用步骤

    • 创建接口及实现类
    • 实现代理处理器:实现 InvokationHandler接口 ,实现 invoke(Proxy proxy,Method method,Object[] args) 方法
    • 通过 Proxy.newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h) 获得代理类
    • 通过代理类调用方法。

Spring AOP的动态代理有两种方式,JDK 动态代理CGLIB(Code Generation Library)动态代理

(1)JDK 动态代理基于接口实现,代理类必须实现InvocationHandler 接口 并通过Proxy 类 的newProxyInstance方法生成动态代理对象,重写invoke方法调用被代理对象的方法。

(2)CGLIB动态代理:CGLIB是用于代码生成类库基于继承实现,运行时动态生成目标类的子类,要求目标类不能被final修饰