当前位置: 首页 > news >正文

ThreadLocal功能实现

模拟ThreadLocal功能实现

当前线程任意方法内操作连接对象

一个栈对应一个线程 , 一个方法调用另一个方法都是在一个线程内 , 只有执行了线程的start方法才会创建一个线程

定义一个Map集合 , key是当前线程(Thread.currentThread) , value是要绑定的数据(Connection对象)

  • 以后获取,绑定,移除数据操作的key就是当前线程 , 当前线程是动态的 , 张三发起请求当前线程是t1线程 , 李四发送请求,当前线程是t2线程

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

ThreadLocal本质

自定义ThreadLocal类 , 将所有需要和当前线程绑定的数据要放到这个容器当中

public class MyThreadLocal<T> {private Map<Thread, T> map = new HashMap<>();//向ThreadLocal中当前线程绑定数据public void set(T obj){map.put(Thread.currentThread(), obj);}//从ThreadLocal中获取当前线程对应的数据public T get(){return map.get(Thread.currentThread());}//移除ThreadLocal当中当前线程对应的数据public void remove(){map.remove(Thread.currentThread());}
}

DBUtil 工具类获取当前线程绑定的Connection对象

public class DBUtil {// 静态变量特点:类加载时执行,并且只执行一次// 全局的大Map集合private static MyThreadLocal<Connection> local = new MyThreadLocal<>();//每一次都调用这个方法来获取Connection对象public static Connection getConnection(){//获取当前线程对应的Connection对象Connection connection = local.get();if (connection == null) {// 第一次调用:getConnection()方法的时候,connection一定是空的。空的就new一次。connection = new Connection();// 将new的Connection对象绑定到大Map集合中。local.set(connection);}return connection;}
}
//自定义Connection对象
public class Connection {   
}

测试从Map集合中获取当前线程绑定的Connection对象

public class Test {public static void main(String[] args) {// 调用serviceUserService userService = new UserService();userService.save();}
}
//UserService
public class UserService {private UserDao userDao = new UserDao();public void save(){//这里获取的就是当前线程绑定的Connection对象Connection connection = DBUtil.getConnection();System.out.println(connection);userDao.insert();}
}
//UserDao
public class UserDao {public void insert(){//这里获取的就是当前线程绑定的Connection对象Connection connection = DBUtil.getConnection();System.out.println(connection);System.out.println("User DAO insert");}
}

使用java.lang.ThreadLocal类优化事务

java.lang.ThreadLocal类中里面有个Map集合 , 这个集合中的key是当前线程 , value是我们想要存储的对象(如存储Connection对象)

  • 这个Map集合中的每个线程都有自己的Connection对象 , 需要的时候根据当前正在执行的线程获取对应的Connection对象
  • 每次获取的Connection对象是从ThreadLocal中的Map集合中拿的 , 第一次获取的时候需要我们手动创建并添加到Map集合中

Connection对象关闭之后,要从大Map集合中移除

  • Tomcat服务器是支持线程池的 , 线程池中有很多提前创建好的线程对象如t1 , t2 , t3 ,它们存在重复使用的问题
  • 就是说一个人用过了t1线程,t1线程还有可能被其他用户使用 , 这时如果你不关闭 , 别人拿到的就是你已经关闭的Connection对象

ThreadLocal的常用方法

方法名功能
public Object get()获取Map集合中当前线程对应的对象 (如Connection对象)
public void set(Object obj)把创建的对象存入Map集合中(如Connection对象)
public void remove()删除Map集合中当前线程对应的对象(如Connection对象)

使用ThreadLocal类优化事务

DBUtil⼯具类:将Connection对象存放到ThreadLocal里面的Map集合中, 保证service和dao中使⽤的Connection对象是同⼀个

public class DBUtil {private static ResourceBundle bundle = ResourceBundle.getBundle("resources/jdbc");private static String driver = bundle.getString("driver");private static String url = bundle.getString("url");private static String user = bundle.getString("user");private static String password = bundle.getString("password");// 工具类中的方法都是静态的,为了防止创建对象,故将构造方法私有化private DBUtil(){}// DBUtil类加载时注册驱动static {try {Class.forName(driver);} catch (ClassNotFoundException e) {e.printStackTrace();}}// 这个Map集合是全局的,在服务器中只有一个private static ThreadLocal<Connection> local = new ThreadLocal<>();//这里没有使用数据库连接池,直接创建连接对象public static Connection getConnection() throws SQLException {//获取当前线程对应的Connection对象,如果没有就创建并把它存入ThreadLocal类中的Map集合中Connection conn = local.get();if (conn == null) {conn = DriverManager.getConnection(url, user, password);local.set(conn);}return conn;}/*** 关闭资源* @param conn 连接对象* @param stmt 数据库操作对象* @param rs 结果集对象*/public static void close(Connection conn, Statement stmt, ResultSet rs){if (rs != null) {try {rs.close();} catch (SQLException e) {throw new RuntimeException(e);}}if (stmt != null) {try {stmt.close();} catch (SQLException e) {throw new RuntimeException(e);}}if (conn != null) {try {// 根本原因是:Tomcat服务器是支持线程池的,也就是说一个人用过了t1线程,t1线程还有可能被其他用户使用conn.close();local.remove();} catch (SQLException e) {throw new RuntimeException(e);}}}
}

不再接收service传过来的Connection对象 , 直接在AccountDao中获取当前线程对应的一个Connection对象

public class AccountDao {//插入账户信息public int insert(Account act) {PreparedStatement ps = null;int count = 0;try {//这里获取的Connection对象是从ThreadLocal中的Map集合中拿的(除了第一次是自己创建的)Connection conn = DBUtil.getConnection();//执行sql....} catch (SQLException e) {throw new RuntimeException(e);} finally {DBUtil.close(null, ps, null);}return count;}//根据主键删除账户public int deleteById(Long id){//执行sql...}//更新账户public int update(Account act) {//执行sql...}//根据账号查询账户public Account selectByActno(String actno){//执行sql...}//获取所有的账户public List<Account> selectAll() {//执行sql...}
}
http://www.lryc.cn/news/165071.html

相关文章:

  • Linux编辑器-vim使用
  • 自助式数据分析平台:JVS智能BI功能介绍(二)数据集管理
  • 《5G技术引领教育信息化新革命》
  • cmake学习过程记录
  • Vue3、Vite使用 html2canvas 把Html生成canvas转成图片并保存,以及填坑记录
  • centos yum源配置(CentOS7 原生 yum 源修改为阿里 yum 源)
  • linux————ansible
  • 初识Java 8-1 接口和抽象类
  • 微信小程序音频后台播放功能
  • NotePad——xml格式化插件xml tools在线安装+离线安装
  • 图书管理系统 数据结构先导课暨C语言大作业复习 | JorbanS
  • python 爬虫的开发环境配置
  • 技术架构图是什么?和业务架构图的区别是什么?
  • 数据增强
  • 【Unity】2D 对话模块的实现
  • laravel安装初步使用学习 composer安装
  • 【VS插件】VS code上的Remote - SSH
  • TensorFlow 02(张量)
  • 513. 找树左下角的值
  • 量化:基于支持向量机的择时策略
  • 成功解决Selenium 中116版本的chromedriver找不到问题
  • PYQT常用组件--方法汇总
  • Linux系统编程(一):文件 I/O
  • OSM+three.js打造3D城市
  • 02JVM_垃圾回收GC
  • ARM Linux DIY(八)USB 调试
  • 编程小白的自学笔记十四(python办公自动化创建、复制、移动文件和文件夹)
  • MySQL使用Xtrabackup备份到AWS存储桶
  • (高阶)Redis 7 第11讲 BIGKEY 优化篇
  • 一阶差分和二阶差分概念及其举例