本文对ThreadLocal类和Future接口进行了总结概括,包括ThreadLocal类的原理、内存泄露等问题,和Future接口的使用等问题。
一、ThreadLocal
1. 介绍
ThreadLocal(线程局部变量)是Java中的一个类,线程通过维护一个本地变量副本,从而保证对该变量的访问不受其他线程的影响。
2. 实现原理
- 每个线程中都有一个ThreadLocalMap 类型的threadLocals 变量和 一个 inheritableThreadLocals 变量
- ThreadLocalMap是ThreadLocal的静态内部类,存储的是以ThreadLocal实例为 key ,Object 对象为 value 的键值对
- 当调用ThreadLocal类实例的get和set方法修改变量值的时候实际上调用的是ThreadLocalMap类的get和set方法,数据实际存储在ThreadLocalMap中
- 源码
① get方法
public T get() {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null) {ThreadLocalMap.Entry e = map.getEntry(this);if (e != null) {@SuppressWarnings("unchecked")T result = (T) e.value;return result;}}return setInitialValue();
}
② set方法
public void set(T value) {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null) {map.set(this, value);} else {createMap(t, value);}
}ThreadLocalMap getMap(Thread t) {return t.threadLocals;
}void createMap(Thread t, T firstValue) {t.threadLocals = new ThreadLocalMap(this, firstValue);
}
3. 内存泄漏问题
(1)虚引用、弱引用、软引用和强引用
- 虚引用:主要用于在对象被回收时,进行一些后续处理工作;必须和引用队列(ReferenceQueue)联合使用
- 弱引用:主要用于实现规范化映射;当垃圾收集器运行时,无论内存是否充足都会回收这些对象
- 软引用:要用于实现内存敏感的缓存;在垃圾收集器判断内存不足时,会回收这些对象
- 强引用:当一个对象被强引用时,垃圾收集器不会回收该对象,即使内存不足也不会回收。通过new对象实例可以创建。
(2)ThreaLocal内存泄露是因为ThreadLocalMap 中的 key 为 ThreadLocal 的弱引用,而 value 是强引用,因此当垃圾回收时会回收ThreadLocal对象实例,而与之对应的value不会被回收,之后该value也不能再使用,由此导致内存泄露。
注:使用ThreadLocal时一定要手动调用remove()方法
二、 Future接口
1. 介绍
Future 接口提供了一种处理异步计算结果的机制,通过使用 Future 和 其实现类FutureTask,可以方便地处理并发编程中的异步任务管理。
2. 常用方法
方法 | 描述 |
---|---|
boolean cancel(boolean mayInterruptIfRunning) | 尝试取消任务的执行。如果任务已完成或已被取消,返回 false 。mayInterruptIfRunning 指示是否应该中断正在执行的任务。 |
boolean isCancelled() | 如果任务在完成前被取消,则返回 true 。 |
boolean isDone() | 如果任务已完成(无论是正常完成、异常终止还是取消),返回 true 。 |
V get() throws InterruptedException, ExecutionException | 等待任务完成并获取结果。如果任务执行过程中抛出异常,则抛出 ExecutionException 。若当前线程被中断,抛出 InterruptedException 。 |
V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException | 在指定时间内等待任务完成并获取结果。如果在指定时间内任务没有完成,抛出 TimeoutException 。若任务执行过程中抛出异常,抛出 ExecutionException 。若当前线程被中断,抛出 InterruptedException 。 |
3. CompletableFuture 和Future之间的区别与联系
特性 | Future | CompletableFuture |
---|---|---|
接口/类 | 接口 | 类(实现了 Future 和 CompletionStage 接口) |
异步任务 | 不能直接表示异步任务,只能表示异步任务的结果 | 可以直接表示异步任务并提供丰富的异步编程支持 |
任务完成通知 | 只能通过阻塞的 get 方法或轮询 isDone 方法检查任务是否完成 | 提供 thenApply , thenAccept , thenRun 等方法来注册回调函数,在任务完成时自动执行 |
手动完成 | 不支持手动完成任务 | 提供 complete , completeExceptionally 等方法手动完成任务 |
组合多个任务 | 不支持直接组合多个任务 | 提供 allOf , anyOf 等方法来组合多个任务 |
异常处理 | 只能通过捕获 ExecutionException 进行异常处理 | 提供 exceptionally , handle , whenComplete 等方法进行异常处理 |
非阻塞获取结果 | 不支持非阻塞地获取结果 | 提供 join , getNow , orTimeout , completeOnTimeout 等方法非阻塞地获取结果或处理超时 |
支持流式 API | 不支持流式 API | 支持流式 API,允许通过链式调用编写更简洁和可读的异步代码 |