ThreadLocal的使用
1、介绍
从java官方文档中的描述:ThreadLocal类用来提供线程内部的局部变量。这种变量在多线程环境下访问(通过get和set方法访问)时能保证各个线程的变量相对独立于其他线程内的变量。ThreadLocal实例通常来说都是private static类型的,用于关联线程和线程上下文我们可以得知 ThreadLocal 的作用是:提供线程内的局部变量,不同的线程之间不会相互干扰,这种变量在线程的生命周期内起作用,减少同一个线程内多个函数或组件之间一些公共变量传递的复杂度。
总结:
1.线程并发: 在多线程并发的场景下
2.传递数据: 我们可以通过ThreadLoca1在同一线程,不同组件中传递公共变量
3.线程隔离: 每个线程的变量都是独立的,不会互相影响
2、基本方法
3、使用案例
3.1、线程不隔离的场景
线程不隔离的场景:
// ------------------------------
//------------------------------
//线程2--->线程3的数据
//------------------------------
//------------------------------
//线程0--->线程2的数据
//------------------------------
//线程3--->线程4的数据
//线程4--->线程4的数据
//线程1--->线程4的数据
// 由于java是抢占式的调度
线程拿到了不属于自己线程的数据,没有实现隔离
package com.hspedu.spring.threadLocal;
/**
* @Author: lihaojie
* @Description: 需求-线程隔离 每个线程中的变量都是互相独立的 线程没有隔离的现象
* @DateTime: 2024/4/18 13:42
**/
public class MyDemo01 {
private String content;
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public static void main(String[] args) {
// ------------------------------
//------------------------------
//线程2--->线程3的数据
//------------------------------
//------------------------------
//线程0--->线程2的数据
//------------------------------
//线程3--->线程4的数据
//线程4--->线程4的数据
//线程1--->线程4的数据
// 由于java是抢占式的调度
MyDemo01 demo = new MyDemo01();
for (int i = 0; i < 5; i++) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
demo.setContent(Thread.currentThread().getName() + "的数据");
System.out.println("------------------------------");
System.out.println(Thread.currentThread().getName() + "--->" + demo.getContent());
}
});
thread.setName("线程" + i);
thread.start();
}
}
}
3.2、使用ThreadLocal实现线程隔离
// ------------------------------
//------------------------------
//线程4--->线程4的数据
//------------------------------
//------------------------------
//线程2--->线程2的数据
//------------------------------
//线程3--->线程3的数据
//线程0--->线程0的数据
//线程1--->线程1的数据 已经解决了线程隔离的问题
package com.hspedu.spring.threadLocal;
/**
* @Author: lihaojie
* @Description: 需求-线程隔离 每个线程中的变量都是互相独立的 使用threadLocal解决
* @DateTime: 2024/4/18 13:42
**/
/**
* ThreadLocal:
* 1. set(): 将变量绑定到当前线程中
* 2. get(): 获取当前线程绑定的变量
* 3.
*/
public class MyDemo02 {
ThreadLocal<String> t1 = new ThreadLocal<>();
private String content;
public String getContent() {
// return content;
return t1.get();
}
public void setContent(String content) {
// this.content = content;
// 绑定到当前线程
t1.set(content);
}
public static void main(String[] args) {
// ------------------------------
//------------------------------
//线程4--->线程4的数据
//------------------------------
//------------------------------
//线程2--->线程2的数据
//------------------------------
//线程3--->线程3的数据
//线程0--->线程0的数据
//线程1--->线程1的数据 已经解决了线程隔离的问题
MyDemo02 demo = new MyDemo02();
for (int i = 0; i < 5; i++) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
demo.setContent(Thread.currentThread().getName() + "的数据");
System.out.println("------------------------------");
System.out.println(Thread.currentThread().getName() + "--->" + demo.getContent());
}
});
thread.setName("线程" + i);
thread.start();
}
}
}
3.3、使用Synchronized解决线程隔离的问题
package com.hspedu.spring.threadLocal;
/**
* @Author: lihaojie
* @Description: 需求-线程隔离 每个线程中的变量都是互相独立的 使用Synchronized加锁来实现线程隔离
* @DateTime: 2024/4/18 13:42
**/
/**
* ThreadLocal:
* 1. set(): 将变量绑定到当前线程中
* 2. get(): 获取当前线程绑定的变量
* 3.
*/
public class MyDemo03 {
private String content;
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public static void main(String[] args) {
MyDemo03 demo = new MyDemo03();
for (int i = 0; i < 5; i++) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
// 加锁
synchronized (MyDemo03.class) {
demo.setContent(Thread.currentThread().getName() + "的数据");
System.out.println("------------------------------");
System.out.println(Thread.currentThread().getName() + "--->" + demo.getContent());
}
}
});
thread.setName("线程" + i);
thread.start();
}
}
}
3.4、ThreadLocal与Synchronized的区别
4、运用场景-事务案例
事务的使用注意点
1.service层和dao层的连接对象保持一致
2.每个线程的connection对象必须前后一致,线程隔离
常规的解决方案:
1、传参,将service层的connection对象传递到dao层
2、加锁
这样做虽然可以解决问题,但是它 提高了代码的耦合度 降低了程序的性能
3、使用ThreadLocal解决
原本:直接从连接池中获取连接
现在:
1.直接获取当前线程绑定的连接对象
如果连接对象是空的
2 .
2.1再去连接池中获取连接
2.2将此连接对象跟当前线程进行绑定
5、ThreadLocal的内部结构
常见的误解:
现在的设计:
1、每个Map存储的entry数量变少,因为之前是每个线程都是map里的一条数据,现在是只有threadLocal才是map里的一条数据,threadLocal的数量肯定是比线程的总数量少的
2、现在放在Thread里,随着Thread的销毁,ThreadLocal也会随之销毁掉,减少了内存的使用,之前并不会随着Thread的销毁而销毁
6、ThreadLocal核心方法源码
6.1、set方法
6.2、get方法
6.3、remove方法
6.4、initialValue方法
7、ThreadLocalMap
7.1、基本结构
8、内存泄露-key为强/弱引用
原文地址:https://blog.csdn.net/weixin_45768501/article/details/137919179
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!