《java并发》--ThreadLocal

Java并发 ThreadLocal 原理(详解) 比如 Tomcat 的线程池处理了一堆请求,而线程池中的线程一般是不会被清理掉的,所以这个引用链就会一直在,那么 ThreadLocal 对象即使没有用了,也会随着线程的存在,而一直存在着。对象作为键都会 计算得到一个hash值,然后和hashMap一样,计算得到entry数组内的一个下标,去查找这个threadLocal对象。实例被不再需要的线程持有为强引用,那么当该线程结束时,相关的 ThreadLocal实例。当然,这种数组操作一般免不了阈值的判断,如果超过阈值则需要进行扩容。 阅读详情

ThreadLocal

认识

ThreadLocal是一个map结构,ThreadLocal.set()默认是用当前线程作为key来使用。

ThreadLocal不是用来解决共享对象的多线程并发问题,而是每个线程都创建一个对象,其他线程访问不到本线程的对象,从而达到线程安全。

如果ThreadLocal.set()进行的对象本来就是多个线程共享的一个对象,还是会出现并发访问的问题。

源码简析

//空构造方法
public ThreadLocal() {
}
//添加元素
public void set(T value) {
  Thread t = Thread.currentThread();
  ThreadLocalMap map = getMap(t);
  //如果不为null,map set值
  if (map != null)
    map.set(this, value);
  else
    //如果为null,创建一个map,key为当前线程
    createMap(t, value);
}
ThreadLocalMap getMap(Thread t) {
  //线程里面持有一个变量ThreadLocal.ThreadLocalMap threadLocals = null; 
  return t.threadLocals;
}
void createMap(Thread t, T firstValue) {
  t.threadLocals = new ThreadLocalMap(this, firstValue);
}
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
  table = new Entry[INITIAL_CAPACITY];
  int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
  table[i] = new Entry(firstKey, firstValue);
  size = 1;
  setThreshold(INITIAL_CAPACITY);
}

//取值
public T get() {
  Thread t = Thread.currentThread();
  ThreadLocalMap map = getMap(t);
  if (map != null) {
    ThreadLocalMap.Entry e = map.getEntry(this);
    if (e != null) {
      @SuppressWarnings("unchecked")
      T result = (T)e.value;
      return result;
    }
  }
  //创建一个key值为当前线程,value为null的map
  return setInitialValue();
}
private T setInitialValue() {
  T value = initialValue();//null
  Thread t = Thread.currentThread();
  ThreadLocalMap map = getMap(t);
  if (map != null)
    map.set(this, value);
  else
    createMap(t, value);//创建map
  return value;
}

用法

InheritableThreadLocal 可以继承父线程的属性值

public class TestThreadLocal{

    static final ThreadLocal<String> threadLocal = new ThreadLocal<String>();
    static final InheritableThreadLocal<String> inheritableThreadLocal = new InheritableThreadLocal<String>();
    public static void main(String[] args) {
        threadLocal.set("主线程局部变量");
        inheritableThreadLocal.set("可继承的父类的局部变量");
        new Thread(new Runnable() {

            @Override
            public void run() {
                System.out.println(threadLocal.get());//null
                System.out.println(inheritableThreadLocal.get());//可继承的父类的局部变量
            }
        }).start();
    }
}

自定义ThreadLocal

public class ThreadLocalTest
{
    private static int data = 1;

    static ThreadLocal threadLocal = new ThreadLocal();
    public static void main(String[] args)
    {
        for (int i = 0; i < 2; i++)
        {
            new Thread(new Runnable()
            {
                @Override
                public void run()
                {
                    int data = new Random().nextInt();
                    MyThreadLocal.getInstance().put("data", data);
                    System.out.println(Thread.currentThread().getName()
                            + " get data " + data);
                    System.out.println(Thread.currentThread().getName()
                            + MyThreadLocal.getInstance());
                    new A().get();
                    new B().get();
                }
            }).start();
        }
    }

    static class A
    {
        public void get()
        {
            System.out.println("A from " + Thread.currentThread().getName()
                    + " get data " + MyThreadLocal.getInstance().get("data"));
        }
    }

    static class B
    {
        public void get()
        {
            System.out.println("B from " + Thread.currentThread().getName()
                    + " get data " + MyThreadLocal.getInstance().get("data"));
        }
    }

    static class MyThreadLocal extends HashMap
    {
        private MyThreadLocal()
        {
        };
        private static MyThreadLocal instance;

        public static MyThreadLocal getInstance()
        {// 因为每个线程不一样对象,所以不需要添加同步
            if (threadLocal.get() == null)
            {
                instance = new MyThreadLocal();
                map.set(instance);
            }
            return (MyThreadLocal) map.get();
        }
    }
}

数据库连接实现线程绑定

import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

import cn.zlz.exception.DaoException;

public class JdbcUtils {

    private JdbcUtils(){}

    private static String url;
    private static String user;
    private static String password;


    private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();

    // 将四要素抽取至配置文件
    static {
        try {
            //读取配置文件   获得四要素
            Properties props = new Properties();
            InputStream inStream = JdbcUtils.class.getClassLoader()
                    .getResourceAsStream("jdbc.properties");
            props.load(inStream);

            String driverClass = props.getProperty("driverClass");
            url = props.getProperty("url");
            user = props.getProperty("user");
            password = props.getProperty("password");

            // 注册驱动
            Class.forName(driverClass);
        } catch (Exception e) {
            throw new ExceptionInInitializerError(e);
        }
    }

    // 获得数据库连接
    public static Connection getConnection() throws SQLException {
        // 返回当前线程绑定的连接  原因是该连接上有事务
        Connection conn = tl.get();
        // 如果conn 为 null    说明线程上未绑定连接
        if(conn==null) {
            // 获得与数据库的连接
            conn = DriverManager.getConnection(url, user, password);
            // 绑定到当前线程
            tl.set(conn);
        }
        return conn;
    }

    // 开启事务
    public static void startTransaction() {
        try {
            // 获得当前线程上绑定的连接
            Connection conn = getConnection();
            // 开启事务
            conn.setAutoCommit(false);
        } catch (SQLException e) {
            throw new DaoException(e);
        }
    }

    // 提交事务
    public static void commit() {
        // 获得当前线程上绑定的连接
        Connection conn = tl.get();
        // 判断
        if(conn!=null) {
            try {
                // 如果线程上有连接 提交该连接事务
                conn.commit();
            } catch (SQLException e) {
                throw new DaoException(e);
            }
        }
    }

    // 回滚事务
    public static void rollback() {
        // 获得当前线程上绑定的连接
        Connection conn = tl.get();
        // 判断
        if(conn!=null) {
            try {
                // 如果线程上有连接 回滚事务
                conn.rollback();
            } catch (SQLException e) {
                throw new DaoException(e);
            }
        }
    }

    // 关闭连接     关闭当前线程上绑定的连接
    public static void close() {
        // 获得当前线程上绑定的连接
        Connection conn = tl.get();
        // 判断
        if(conn!=null) {
            try {
                // 如果线程上有连接 关闭连接
                conn.close();
            } catch (SQLException e) {
                throw new DaoException(e);
            }
            // 移除当前线程绑定的 connnection 对象
            tl.remove();
        }
    }

    public static void release(Connection conn, Statement stmt, ResultSet rs) {
        if(rs!=null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            rs = null;
        }

        if(stmt!=null) {
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            stmt = null;
        }

        if(conn!=null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            conn = null;
        }
    }
}
【Java并发编程】ThreadLocal由浅入深说 不要停留在用,一文带你了解ThreadLocal底层 阅读详情

相关推荐

多租户Saas架构设计分析(基础篇)

本篇先给大家介绍一下相关的概念和常见问题。 实践篇链接:https://blog.youkuaiyun.com/haponchang/article/details/104246317 SaaS简介 SaaS是Software-as-a-Service(软件即服务)的简称,“软件即服务”?是不是有点拗口?其实你就理解成为“按需租用别人提供的软件服务”就可以了,它是一种软件交付模式。...

haponchang的博客 1万+

ThreadLocal 基本原理与set源码解析

看文章前先了解java弱引用和多线程 简介 当我们想要多个线程使用同一个变量时,会出现并发安全问题,这时候我们必须采取措施,对变量的访问进行同步。 为了达到这个目的,我们一般是采用加锁的方式解决,但是加锁的方式太重了,会使系统的并发量大大降低,有什么办法能够解决这个问题呢? 当然有,不过是另辟蹊径: 不对访问进行同步,而是对每个线程,复制一份该变量,每个线程操作自己的那部分变量,来消除并发安全。Threadlocal就是用来干这个的 Threadlocal的使用 public class MyThrea.

HeiheiChihiro的博客 780

LibTV保姆级教程:从提示词到AI视频成片全流程

AI视频生成技术正以前所未有的速度重塑内容创作行业,过去需要编剧、摄影、剪辑等多角色协作的复杂流程,如今借助AI绘画与图生视频等核心能力,一个人也能完成高质量短视频制作。理解提示词工程是掌控AI视频创作的关键,通过精准描述主体、环境、光线与运镜,可以显著提升生成画面的稳定性与专业度。而图生视频技术则让静态分镜自然流动,有效解决角色一致性与场景漂移等常见问题。这类工具已广泛应用于产品宣传、剧情短片、社交媒体内容生产等场景,大幅降低了视频创作门槛。本文以LibTV一站式AI视频创作平台为例,从核心概念到完整实操

weixin_29046035的博客 938

ThreadLocal分析二:set()方法解读

ThreadLocal的Set()方法

Chen_leilei的博客 3555

silvaco例子库学习—mos1ex02

mos1ex02相比于第一个例子,主要进行了mos的输出特性仿真,工艺结构是一样的,所以就只简单讨论一下atlas特性仿真的部分。

weixin_61913839的博客 852

ESP32 Arduino 学习篇(五)TFT_eSPI库

该库有User_Setup.h和 User_Setup_Select.h两个配置文件,支持 ①自定义参数或 ②使用已有配置 驱动TFT屏幕。优点是: 1. 占用空间非常小 2. 动画清晰,充分利用每个像素点 3. 可以非常灵动. 4. 方便进行微调。首先在Libraries里面搜索安装TFT_eSPI库到你的工程文件里面。初始化屏幕, 如果是ST7735,可以往里面传一个参数, 具体用到时再看。缺点是: 1. 容易闪屏 2. 一般不会太复杂 3.需要大量的计算。特别注意: 字库7是仿7段数码屏的样式。

DOF526570的博客 2万+

ThreadLocal set方法解析

ThreadLocal 源码 原理

weixin_38965431的博客 4774

下载和运行GitHub上的代码教程总结

从昨天开始就想着从GitHub上下载一个开源的Vue的实战项目,希望能从中学习更多的Vue的实用内容,结果搞了半天好不容易下载了,不知道怎么弄。然而,今天终于成功了,激动地我赶紧来记录一下。 如何从GitHub上下载自己需要的项目: 1.首先,你要有一个自己的GitHub(https://github.com/)的账号。关于如何注册GitHub的账号以及如何获取你的SSH密钥这个问题,请大家参...

不怕万人阻挡,只怕自己投降 29万+

Java并发——ThreadLocal总结

并发问题,有时候,可以用ThreadLocal方式来避免。ThreadLocal,顾名思义,就是线程自己的,独享的,就像线程栈是线程独享的一样。

BASK2311的博客 984

YOLO26原创自研: 魔改Bottleneck,具备多尺度和特征通道融合的结构

魔改Bottleneck,具备多尺度和特征通道融合的结构,该模型在检测准确性方面都取得了良好的效果,尤其在缺陷检测方向。

①答疑群聊服务;②YOLO大模型知识问答系统;③计算机视觉论文生成智能体; 315

001、NPU是什么?为什么嵌入式设备需要它?

本文通过作者调试工业相机板卡的经历,引出嵌入式设备为何需要NPU(神经网络处理器)的探讨。文章对比了CPU和NPU的设计哲学差异,指出NPU通过专用乘加器阵列和优化的数据流,能高效处理神经网络运算。作者分析了嵌入式设备使用NPU的三大优势:算力提升、功耗降低和实时性保障,并介绍了三类常见NPU形态。通过一个YOLOv5模型调试案例,揭示了NPU使用中的常见陷阱,最后给出五条实用建议,强调理解NPU原理和局限的重要性。文章生动展现了NPU在嵌入式AI应用中的关键作用。

m0_50546716的博客 125

java并发之ThreadLocal

ThreadLocal的思考: 描述: 方法1:传入秒数,new一个SimpleDataFormat对象,返回时间字符串 方法2:生成两个线程,每个线程都去调用方法1来打印不同秒数的时间 结果:运行正常 进一步思考:要是1000个线程呢?用线程池,生成10线程 进一步思考:在方法1中,每次调用都会new一个SimpleDataFormat对象,浪费开销 解决方法:将S...

简单点,编程的方式简单点 270

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

【Java 并发】详解 ThreadLocal

前言 ThreadLocal 主要用来提供线程局部变量,也就是变量只对当前线程可见,本文主要记录一下对于 ThreadLocal 的理解。更多关于 Java 多线程的文章可以转到 这里。 线程局部变量 在多线程环境下,之所以会有并发问题,就是因为不同的线程会同时访问同一个共享变量,例如下面的形式 public class MultiThreadDemo { public static class Number { private int value = 0; pu

weixin_53341657的博客 257

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

Java 并发 - ThreadLocal原理

Java 并发 - ThreadLocal原理 线性探测

杨宇昌的博客 398

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

Java并发编程之 ThreadLocal

多线程访问同一个共享变量的时候容易出现并发问题,特别是多个线程对一个变量进行写入的时候,为了保证线程安全,一般使用者在访问共享变量的时候需要进行额外的同步措施才能保证线程安全性。ThreadLocal是除了加锁这种同步方式之外的另一种保证一种规避多线程访问出现线程不安全的方法,当我们在创建一个变量后,如果每个线程对其进行访问的时候访问的都是线程自己的变量这样就不会存在线程不安全问题。 ThreadLocal是JDK包提供的,它提供线程本地变量,如果创建一个ThreadLocal变量,那么访问这个变量的每个线

qq_43613793的博客 582

Java并发编程——ThreadLocal

ThreadLocal详解

m0_62909831的博客 1243

java并发编程之ThreadLocal

不管用那种语言,在并发编程中遇见的问题都是类似的,只不每种语言提供的方法和工具不一样而已。 对于每个线程独享某个对象或者每个线程独立保存信息的场景,java提供的解决方法是ThreadLocal , 对于线程独享某个对象的例子 public class ThreadLocalDemo { public static ExecutorService threadPool = Executors.newFixedThreadPool(16); SimpleDateFormat dateForma

acethan的博客 186

Java并发-ThreadLocal

ThreadLocal的作用 作用是为每个线程保存线程私有数据。可以把ThreadLocal理解为一个Map,其中key为当前线程,value为要存储的数据。 下面是摘自《Java编程思想》中的一段示例代码: public class ThreadLocalTest { public static void main(String[] args) throws Exceptio...

不瘦十斤不换名字 576

ThreadLocal实战:Java并发编程中的利器

要点 | 描述 || ThreadLocal | 用于线程隔离的利器,适用于高并发场景 || 线程安全 | 通过为每个线程绑定变量副本实现线程之间的数据隔离 || 性能 | 高吞吐量、低延迟 |ThreadLocal是Java并发编程中的利器,在高并发场景下,可以有效解决线程安全问题。随着技术的不断发展,ThreadLocal将在更多场景中得到应用。未来,我们期待看到更多关于ThreadLocal的创新和突破。

南客先生的博客 871

java threadlocal 并发_java 并发,为线程创建本地变量 ThreadLocal的使用

packagetest;publicclassThreadLocalTest{publicstaticvoidmain(String[]args){ThreadLocaltl=newThreadLocal();Locall=newLocal();ThreadAta=newThreadA(tl);ThreadAtb=newThreadA(tl);ta...

weixin_39787089的博客 95

[Java][并发]ThreadLocal分析

nanchengyu的博客 150

【Java并发】ThreadLocal

ThreadLocal是java.lang下面的一个类,是用来解决java多线程程序中并发问题的一种途径;通过为每一个线程创建一份共享变量的副本来保证各个线程之间的变量的访问和修改互相不影响;ThreadLocal存放的值是线程内共享的,线程间互斥的,主要用于线程内共享一些数据,避免通过参数来传递,这样处理后,能够优雅的解决一些实际问题。

xueping_wu的博客 785

java threadlocal 并发_Java 并发之 ThreadLocal

1.1 什么是 ThreadLocalThreadLocal 简单理解 Thread 即线程,Local 即本地,结合起来理解就是 每个线程都是本地独有的。在早期的计算机中不包含操作系统,从头到尾只执行一个程序,并且这个程序能访问计算中的所有资源,这对于计算机资源来说是一种浪费。要想充分发挥多处理器的强大计算能力,最简单的方式就是使用多线程。与串行程序相比,在并发程序中存在更多容易出错的地方。当访...

weixin_30635707的博客 151

Java并发编程-ThreadLocal总结

ThreadLocal并不属于java.util.concurrent.*包的内容,但却是并发编程中很重要也比较常用的一个类,它的核心思想是数据隔离。 1.ThreadLocal作用 在并发编程中时常有这样一种需求:每条线程都需要存取一个同名变量,但每条线程中该变量的值均不相同。 如果是你,该如何实现上述功能?常规的思路如下: 使用一个线程共享的Map<Thread,Object>,M...

冒烟儿的专栏 499
上一篇: 《设计模式》-- 模板方法模式
下一篇: 《设计模式》-- 迭代器模式
fight_zhi
博客等级 码龄14年 27粉丝 66原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值