1、static 的必要性:全局唯一实例

问题示例(非静态):

public class UserService {

// 错误:每个实例都有自己的 ThreadLocal

private ThreadLocal userThreadLocal = new ThreadLocal<>();

public void process() {

userThreadLocal.set(new User());

}

}

// 使用时会创建多个 ThreadLocal 实例

UserService service1 = new UserService();

UserService service2 = new UserService();

// 每个实例都有独立的 ThreadLocal,导致内存浪费

正确示例(静态):

public class UserContext {

// 正确:所有实例共享同一个 ThreadLocal

private static final ThreadLocal userThreadLocal = new ThreadLocal<>();

public static void setUser(User user) {

userThreadLocal.set(user);

}

}

2、final 的必要性:防止重新赋值

final 防止的内存泄漏场景:

public class DangerousExample {

private static ThreadLocal threadLocal = new ThreadLocal<>();

public void dangerousMethod() {

// 某个业务逻辑中重新赋值

threadLocal = new ThreadLocal<>(); // 没有 final,可以重新赋值

// 原来的 ThreadLocal 实例失去引用,但线程中仍有旧值

// 导致内存泄漏:线程的 ThreadLocalMap 中仍有旧 Entry

}

}

final 的正确用法:

public class SafeExample {

// final 防止重新赋值

private static final ThreadLocal USER_CONTEXT =

ThreadLocal.withInitial(() -> null);

// 编译错误:无法重新赋值

// USER_CONTEXT = new ThreadLocal<>();

}

如果没有 final:

ThreadLocal 实例被重新赋值

原来的实例只有弱引用指向

GC 会回收原来的 ThreadLocal 实例

但值对象仍然被强引用,导致内存泄漏

3、内存模型对比

非 static final 的内存风险

static final 的内存安全

4、初始化安全性保证

public class SafeInitialization {

// static final 保证初始化线程安全

private static final ThreadLocal DATE_FORMAT =

ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));

// 多线程环境下安全访问

public static String formatDate(Date date) {

return DATE_FORMAT.get().format(date);

}

}

示例1:数据库连接管理

public class ConnectionManager {

// static final 确保全局唯一且安全

private static final ThreadLocal CONNECTION_HOLDER =

new ThreadLocal<>();

public static Connection getConnection() throws SQLException {

Connection conn = CONNECTION_HOLDER.get();

if (conn == null || conn.isClosed()) {

conn = DataSource.getConnection();

CONNECTION_HOLDER.set(conn);

}

return conn;

}

public static void closeConnection() throws SQLException {

Connection conn = CONNECTION_HOLDER.get();

if (conn != null) {

CONNECTION_HOLDER.remove();

conn.close();

}

}

}