ThreadLocal localUser = new ThreadLocal()
public class SessionUserUtil {
private static ThreadLocal<User> localUser = new ThreadLocal<User>();
public static User getSessionUser() {
return localUser.get();
}
public static void setSessionUser(User user) {
localUser.set(user);
}
}
使用:
service中需要使用登录用户User时候如下:
User user = SessionUserUtil.getSessionUser();
解释:
ThreadLocal
是 Java 中一个特殊的类,它提供了线程本地存储(Thread-local storage)功能。当一个 ThreadLocal
对象被创建后,在每个线程中都会创建一个副本,每个线程都可以独立地操作自己的副本,而不会干涉其他线程的数据。
具体地说,ThreadLocal
通过为每个线程提供一个独立的变量副本解决了多线程代码中的线程安全问题,从而避免了使用传统的同步机制(如 synchronized
等)导致的性能下降等问题。
在上面的代码中,ThreadLocal<User> localUser = new ThreadLocal<User>()
创建了一个 ThreadLocal
对象,其中 User
是我们想要在线程之间共享的对象类型。在使用时,我们可以通过 localUser.get()
获取当前线程存储的 User
对象,以及通过 localUser.set(User user)
将指定的 User
对象存储到当前线程中。
总之,ThreadLocal
为我们在多线程环境下提供了一种简单而有效的线程本地存储方式,通过避免线程安全问题,提高了代码的性能和可靠性。
其他应用场景:
以下是两个使用ThreadLocal的实际例子:
- 线程安全地生成唯一ID
在Web应用中,可能需要为每个请求生成一个唯一的ID,可以使用UUID来生成ID,但是每次生成都需要创建一个新的UUID对象,而且多线程环境下使用较为麻烦。使用ThreadLocal可以为每个线程绑定一个唯一的ID生成器对象,每次需要生成ID时,直接从当前线程绑定的ID生成器对象中获取即可。代码示例:
public class UniqueIDGenerator {
private static ThreadLocal<UUID> uuidThreadLocal = ThreadLocal.withInitial(() -> UUID.randomUUID());
public static String generateID() {
return uuidThreadLocal.get().toString();
}
}
在多线程环境下,每个线程都独立的获取UUID,并且保证了生成的ID是唯一的。
- 线程安全地使用数据库连接对象
在Web应用中,可能需要在Service层中使用DAO对象来访问数据库,而一个DAO对象通常需要使用同一个数据库连接对象,在多线程环境下使用较为麻烦。使用ThreadLocal可以将该连接对象与当前线程绑定,每次需要使用该连接对象时,直接从当前线程绑定的连接对象中获取即可。代码示例:
public class MyDao {
private static ThreadLocal<Connection> connectionThreadLocal = new ThreadLocal<>();
public void doSomething() {
Connection conn = connectionThreadLocal.get();
if (conn == null) {
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "123456");
connectionThreadLocal.set(conn);
}
// 使用连接对象进行操作
// ...
}
}
在多线程环境下,每个线程都独立地使用自己的连接对象,避免了线程之间的相互影响。