ThreadLocal应用场景

ThreadLocal应用场景

一、会话用户信息管理

​ 在一个使用 Web 技术的应用中,通常需要管理用户的会话状态。每个用户请求都在一个独立的线程中处理,但每个线程都需要访问用户的会话数据。

  • 案例如下:
public class UserSessionManager {
    private static ThreadLocal userSessionThreadLocal = new ThreadLocal<>();

    public static void setUserSession(UserSession userSession) {
        userSessionThreadLocal.set(userSession);
    }

    public static UserSession getUserSession() {
        return userSessionThreadLocal.get();
    }

    public static void clearUserSession() {
        userSessionThreadLocal.remove();
    }
}

在上面的示例中,UserSessionManager 类使用 ThreadLocal 来管理用户会话数据。当用户登录时、或登陆后(主要是登陆后、从token中解析用户信息,从而放到threadlocal中),可以将用户会话数据设置到 ThreadLocal 中:

UserSession userSession = new UserSession(userId, userName);
UserSessionManager.setUserSession(userSession);

二、数据库连接管理-jdbc

ThreadLocal 来在每个线程中存储数据库连接,从而确保每个线程都使用自己的连接,避免线程间的竞争和资源管理问题。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class JdbcUtils {
    // 数据库驱动名和数据库URL
    private static final String DRIVER = "com.mysql.cj.jdbc.Driver";
    private static final String URL = "jdbc:mysql://localhost:3306/mysql-student?serverTimezone=UTC";

    // 数据库用户名和密码
    private static final String USERNAME = "root";
    private static final String PASSWORD = "root";

    // 使用 ThreadLocal 来维护数据库连接的线程隔离
    private static ThreadLocal connectionHolder = new ThreadLocal<>();

    // 获取数据库连接
    public static Connection getConnection() throws SQLException {
        // 先从 ThreadLocal 中获取连接
        Connection connection = connectionHolder.get();
        // 如果没有连接,则创建一个新连接,并将其保存到 ThreadLocal 中
        if (connection == null) {
            connection = DriverManager.getConnection(URL, USERNAME, PASSWORD);
            connectionHolder.set(connection);
        }
        return connection;
    }

    // 释放数据库连接
    public static void releaseConnection() {
        Connection connection = connectionHolder.get();
        try {
            if (connection != null) {
                connection.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 清空 ThreadLocal 中的连接
            connectionHolder.remove();
        }
    }

    // 执行 SQL 查询语句
    public static ResultSet executeQuery(String sql, Object... params) throws SQLException {
        PreparedStatement ps = getConnection().prepareStatement(sql);
        if (params != null && params.length > 0) {
            for (int i = 0; i < params.length; i++) {
                ps.setObject(i + 1, params[i]);
            }
        }
        return ps.executeQuery();
    }

    // 执行 SQL 更新语句
    public static int executeUpdate(String sql, Object... params) throws SQLException {
        PreparedStatement ps = getConnection().prepareStatement(sql);
        if (params != null && params.length > 0) {
            for (int i = 0; i < params.length; i++) {
                ps.setObject(i + 1, params[i]);
            }
        }
        return ps.executeUpdate();
    }

    public static void main(String[] args) throws SQLException {
        System.out.println(getConnection());
        System.out.println(getConnection()==getConnection());
    }

}

三、用户请求上下文

在 Web 应用中,可以使用 ThreadLocal 来存储用户请求的上下文信息,如请求的参数、请求的路径等。这样在处理请求时,可以方便地获取这些信息,而不需要将它们传递到每个方法中。

public class UserRequestContext {
    private static ThreadLocal<Map<String, String>> contextThreadLocal = ThreadLocal.withInitial(HashMap::new);

    public static void setAttribute(String key, String value) {
        contextThreadLocal.get().put(key, value);
    }

    public static String getAttribute(String key) {
        return contextThreadLocal.get().get(key);
    }

    public static void clear() {
        contextThreadLocal.get().clear();
    }
}

// 在请求处理过程中
UserRequestContext.setAttribute("userId", "123");
UserRequestContext.setAttribute("username", "john");

// 在不同的方法中访问
String userId = UserRequestContext.getAttribute("userId");
String username = UserRequestContext.getAttribute("username");

四、线程池中的任务隔离

在使用线程池执行任务时,如果每个任务需要独立的环境或状态,可以使用 ThreadLocal 来确保每个任务都具有自己的状态,而不会相互干扰。

public class TaskContext {
    private static ThreadLocal<String> taskIdThreadLocal = new ThreadLocal<>();

    public static void setTaskId(String taskId) {
        taskIdThreadLocal.set(taskId);
    }

    public static String getTaskId() {
        return taskIdThreadLocal.get();
    }

    public static void clear() {
        taskIdThreadLocal.remove();
    }
}

ExecutorService executorService = Executors.newFixedThreadPool(5);

for (int i = 0; i < 10; i++) {
    final int taskId = i;
    executorService.submit(() -> {
        TaskContext.setTaskId("Task-" + taskId);
        System.out.println("Executing task: " + TaskContext.getTaskId());
        // 在任务中访问任务特定的上下文信息
        TaskContext.clear();
    });
}

executorService.shutdown();

五、日志跟踪

略。常见就1-3~

你可能感兴趣的:(java,jdbc)