线程变量的特点
-
多线程环境下,每个线程都有自己的数据
-
一个线程的局部变量只有自己能看见,不会影响其他线程(使用局部变量比使用其他变量好)
ThreadLocal的特点
-
ThreadLocal能够放一个线程级别的变量
-
本身能够被多个线程共享使用,又能达到线程安全的目的
-
在多线程环境下保证成员变量的安全
常用方法:
get/set/initialValue(初始化)方法
JDK建议ThreadLocal定义为private static
ThreadLocal常用的地方(内部存储结构类似于Map)
-
为每一个线程绑定一个数据库连接(每一个线程有一个数据库连接)、HTTP请求、用户身份信息等
-
Hibernate的Session 工具类HibernateUtil
-
通过不同的线程对象设置Bean属性,保证各个线程Bean对象的独立性
-
-
每个线程拥有一个ThreadLocal
-
ThreadLocal内部的存储结构类似于Map
-
key是线程信息
-
value是对应的存储内容
-
这样可以达到每个线程的数据相互独立,又可以共享一块大的区域。达到在多线程环境下保证成员变量的安全。
-
-
ThreadLocal的实例demo
package thread.rearrangement;
/**
* ThreadLocal:每个线程自身的存储区域(局部)
* get/set/initialValue
* @since JDK 1.8
* @date 2021/6/22
* @author Lucifer
*/
public class ThreadLocalTestNo1 {
/*声明类属性*/
// private static ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
/*更改初始值--->创建threadlocal的子类,重写initialValue*/
// private static ThreadLocal<Integer> threadLocal = new ThreadLocal<>(){
// protected Integer initialValue(){
// return 200; //初始化的值就更改成了200
// };
// };
/*lambda表达式更改初始值*/
// private static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> {
// return 200;
// });
/*更加简化代码*/
private static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 200);
/*
这样就开辟了一个大的存储空间
每来一个线程都会自动开辟一个区域
这些开辟的空间都会在大的存储空间内
*/
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName() + "--->" + threadLocal.get());
/*因为是整数,所以默认值是Null,不是零*/
/*设置值*/
threadLocal.set(99);
System.out.println(Thread.currentThread().getName() + "--->" + threadLocal.get());
/*
现在所有的存储区域属于主线程main
*/
/*实例化线程内部类*/
new Thread(new MyRun()).start();
}
/**
* 写一个内部类,实现Runnable接口
* 线程类
*/
public static class MyRun implements Runnable{
/*重写run方法*/
ThreadLocal修改属性变量的实例demo
package thread.rearrangement;
/**
* 每个线程存储自己的数据,更改不会影响其他线程
* @since JDK 1.8
* @date 2021/6/23
* @author Lucifer
*/
public class ThreadLocalTestNo2 {
/*更加简化代码*/
private static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 1);
/*
这样就开辟了一个大的存储空间
每来一个线程都会自动开辟一个区域
这些开辟的空间都会在大的存储空间内
*/
public static void main(String[] args) {
for (int i=0; i<5; i++){
new Thread(new MyRun()).start();
}
}
/**
* 写一个内部类,实现Runnable接口
* 线程类
*/
public static class MyRun implements Runnable{
/*重写run方法*/
ThreadLocal调用分析
package thread.rearrangement;
/**
* 分析ThreadLocal环境
* @since JDk 1.8
* @date 2021/6/23
* @author Lucifer
*/
public class ThreadLocalTestNo3 {
/*创建ThreadLocal存储空间*/
private static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 1);
public static void main(String[] args) {
new Thread(new MyRun()).start();
new Thread(new MyRun()).start();
}
/**
* 创建一个内部线程类
*/
public static class MyRun implements Runnable{
/*写一个构造器*/
public MyRun(){
threadLocal.set(-100);
System.out.println(Thread.currentThread().getName() + "--->" + threadLocal.get());
}
/*重写Runnable接口的run方法*/
InheritableThreadLocal拷贝线程数据实例
package thread.rearrangement;
/**
* InheritableThreadLocal:继承上下文、环境的数据、起点
* @since JDK 1.8
* @date 2021/6/23
* @author Lucifer
*/
public class ThreadLocalTestNo4 {
/*开辟ThreadLocal线程空间*/
private static InheritableThreadLocal<Integer> threadLocal = new InheritableThreadLocal<>();
public static void main(String[] args) {
/*设置值*/
threadLocal.set(2);
/*线程属性变量*/
System.out.println(Thread.currentThread().getName() + "--->" + threadLocal.get());
/*修改拷贝的属性*/
threadLocal.set(200);
/*
这样修改以后上面的线程就是初始设置的2
下面的新的线程为现在设置的200
*/
/*新建一个线程体*/
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "--->" + threadLocal.get());
}).start();
/*
这是新的线程体的,他的值是null
如果将ThreadLocal改为InheritableThreadLocal那么set值就会被延续到下一个线程体当中
因为新建的线程由main线程开辟,所以会将数据拷贝一份给子线程
这是拷贝不是共享,所以新的线程体还可以对属性进行修改
*/
}
}