ThreadLocal应用场景

news/2024/5/19 0:27:35 标签: java, jdbc

ThreadLocal应用场景

一、会话用户信息管理

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

  • 案例如下:
public class UserSessionManager {
    private static ThreadLocal<UserSession> 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_37">二、数据库连接管理-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<Connection> 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 来存储用户请求的上下文信息,如请求的参数、请求的路径等。这样在处理请求时,可以方便地获取这些信息,而不需要将它们传递到每个方法中。

java">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 来确保每个任务都具有自己的状态,而不会相互干扰。

java">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~


http://www.niftyadmin.cn/n/4954625.html

相关文章

基于SSM的校园旧书交易交换网站

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…

Python functools module 的介绍与应用

Python functools module 的介绍与应用 functools module lru_cache from functools import lru_cache import timelru_cache(maxsizeNone) # 设置缓存大小为无限制 def my_function(x):for i in range(1000):x xfor j in range(100):x xreturn x# 第一次调用函数&#xff…

Unity C# 引用池 ReferencePool

Unity C# 引用池 ReferencePool 1.目的 对于多次创建的数据使用new 关键字是十分消耗性能的&#xff0c;使用完成后由GC去自动释放&#xff0c;当一个类型的数据频繁创建可以使用引用池进行管理。 2.实现 项目目录 IReference 接口 要放入引用池的数据只需要继承这个接口…

【数据结构OJ题】链表的回文结构

原题链接&#xff1a;https://www.nowcoder.com/practice/d281619e4b3e4a60a2cc66ea32855bfa?tpId49&&tqId29370&rp1&ru/activity/oj&qru/ta/2016test/question-ranking 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 在做这道…

VINS-Mono中的边缘化与滑窗 (4)——VINS边缘化为何是局部变量边缘化?

文章目录 0.前言1.系统构建1.1.仿真模型1.2.第一次滑窗优化1.3.第二次全局优化 2.边缘化时不同的舒尔补方式2.1.边缘化时舒尔补的意义2.2.不同的边缘化方式 3.边缘化时不同的舒尔补方式实验验证3.1.全局schur的操作方式3.2.VIO或VINS中局部边缘化的方式3.3.两种方式和全局优化方…

LeetCode题解:617. 合并二叉树,JavaScript,详细注释

原题链接&#xff1a; https://leetcode.cn/problems/merge-two-binary-trees/ 这是一道关于二叉树的题目&#xff0c;要求我们合并两棵二叉树。合并的规则是&#xff1a;如果两个节点重叠&#xff0c;那么将这两个节点的值相加作为合并后节点的新值&#xff1b;否则&#xff…

spring发送邮件笔记

文章目录 引入依赖配置代码附件url地址为空会不会报错接收方邮件地址错误会不会报错 引入依赖 推荐用spring集成依赖&#xff0c;不用一个包一个包找了。 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-…

漏洞指北-VluFocus靶场专栏-工具篇

漏洞指北-VluFocus靶场专栏-番外篇奇技淫巧 &#x1f338;1、burp suite 、中国蚁剑工具、Strut2扫描软件地址&#x1f338;&#x1f338;2、burp suite使用&#x1f338;step1 浏览器开启代理&#xff0c;**推荐使用&#xff1a;SwitchyOmega** step2 确认浏览器端口和burp su…