设为首页 加入收藏

TOP

ThreadLocal的介绍与运用(五)
2023-07-25 21:31:16 】 浏览:98
Tags:ThreadLocal
连接 conn.close(); } catch (SQLException e) { e.printStackTrace(); } } public static void rollbackAndClose() { try { Connection conn = getConnection(); //回滚事务 conn.rollback(); //解除绑定 tl.remove(); //释放连接 conn.close(); } catch (SQLException e) { e.printStackTrace(); } } }

? (2) AccountService类的修改:不需要传递connection对象

package com.itheima.transfer.service;

import com.itheima.transfer.dao.AccountDao;
import com.itheima.transfer.utils.JdbcUtils;
import java.sql.Connection;

public class AccountService {

    public boolean transfer(String outUser, String inUser, int money) {
        AccountDao ad = new AccountDao();

        try {
            Connection conn = JdbcUtils.getConnection();
            //开启事务
            conn.setAutoCommit(false);
            // 转出 : 这里不需要传参了 !
            ad.out(outUser, money);
            // 模拟转账过程中的异常
//            int i = 1 / 0;
            // 转入
            ad.in(inUser, money);
            //事务提交
            JdbcUtils.commitAndClose();
        } catch (Exception e) {
            e.printStackTrace();
            //事务回滚
           JdbcUtils.rollbackAndClose();
            return false;
        }
        return true;
    }
}

? (3) AccountDao类的修改:照常使用

package com.itheima.transfer.dao;

import com.itheima.transfer.utils.JdbcUtils;

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

public class AccountDao {

    public void out(String outUser, int money) throws SQLException {
        String sql = "update account set money = money - ? where name = ?";
        Connection conn = JdbcUtils.getConnection();
        PreparedStatement pstm = conn.prepareStatement(sql);
        pstm.setInt(1,money);
        pstm.setString(2,outUser);
        pstm.executeUpdate();
        //照常使用
//        JdbcUtils.release(pstm,conn);
        JdbcUtils.release(pstm);
    }

    public void in(String inUser, int money) throws SQLException {
        String sql = "update account set money = money + ? where name = ?";
        Connection conn = JdbcUtils.getConnection();
        PreparedStatement pstm = conn.prepareStatement(sql);
        pstm.setInt(1,money);
        pstm.setString(2,inUser);
        pstm.executeUpdate();
//        JdbcUtils.release(pstm,conn);
        JdbcUtils.release(pstm);
    }
}

2.3.2 ThreadLocal方案的好处

从上述的案例中我们可以看到, 在一些特定场景下,ThreadLocal方案有两个突出的优势:

  1. 传递数据 : 保存每个线程绑定的数据,在需要的地方可以直接获取, 避免参数直接传递带来的代码耦合问题

  2. 线程隔离 : 各线程之间的数据相互隔离却又具备并发性,避免同步方式带来的性能损失

3. ThreadLocal的内部结构

? 通过以上的学习,我们对ThreadLocal的作用有了一定的认识。现在我们一起来看一下ThreadLocal的内部结构,探究它能够实现线程数据隔离的原理。

3.1 常见的误解

? 通常,如果我们不去看源代码的话,我猜ThreadLocal是这样子设计的:每个ThreadLocal类都创建一个Map,然后用线程的ID threadID作为Mapkey,要存储的局部变量作为Mapvalue,这样就能达到各个线程的局部变量隔离的效果。这是最简单的设计方法,JDK最早期的ThreadLocal就是这样设计的。

3.2 核心结构

? 但是,JDK后面优化了设计方案,现时JDK8 ThreadLocal的设计是:每个Thread维护一个ThreadLocalMap哈希表,这个哈希表的keyThreadLocal实例本身,value才是真正要存储的值Object

? (1) 每个Thread线程内部都有一个Map (ThreadLocalMap)
? (2) Map里面存储ThreadLocal对象(key)和线程的变量副本(value)
? (3)Thread内部的Map是由ThreadLocal维护的,由ThreadLocal负责向map获取和设置线程的变量值。
? (4)对于不同的线程,每次获取副本值时,别的线程并不能获取到当前线程的副本值,形成了副本的隔离,互不干扰。

1574155226793

3.3 这样设计的好处

? 这个设计与我们一开始说的设计刚好相反,这样设计有如下两个优势:

(1) 这样设计之后每个Map存储的Entry数量就会变少,因为之前的存储数量由Thread的数量决定,现在是由ThreadLocal的数量决定。

(2) 当Thread销毁之后,对应的ThreadLocalMap也会随之销毁,能减少内存的使用。

4. ThreadLocal的核心方法源码

? 基于ThreadLocal的内部结构,我们继续探究一下ThreadLocal的核心方法源码,更深入的了解其操作原理。

除了构造之外, ThreadLocal对外暴露的方法有以下4个:

方法声明 描述
protected T initialValue() 返回当前线程局部变量的初始值
public void set( T value) 设置当前线程绑定的局部变量
public T get() 获取当前线程绑定的局部变量
public void remove() 移除当前线程绑定的局部变量

其实get,set

首页 上一页 2 3 4 5 6 7 8 下一页 尾页 5/8/8
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇MybatisPlus Lambda表达式 聚合查.. 下一篇MyBatis笔记04-----分页查询、res..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目