多线程_高级主题_ThreadLocal
这个ThreadLocal表示的是每个线程本地存储区域,也就是每个线程的一亩三分地。可以把ThreadLocal看作是银行,每个银行里面有很多保险箱,每个线程有自己的保险箱,每个客户就相当于每个线程,它内部的存储结构类似于一个map,key是线程的信息,value对应的是存储的内容,也就是数据。这样做的好处是保证了每个线程的数据相互独立,同时又可以共享银行这个大的区域。这样就能达到每个线程级别的数据的存储,达到在多线程环境下保证【成员变量】的安全,因为每个数据只有线程自己能够看得到,别的线程是看不到的,不会影响其他线程。
ThreadLocal官方建议使用private static来修饰,达到线程间共享。
使用ThreadLocal常用的方法有3个:
1、set:设置值
2、get:得到值
3、initialValue:初始化
ThreadLocal后期也会用,一般来说是用在跟每一个线程相关的东西。比如说每一个线程有自己的数据库的连接,这样大家相互不影响;或者我们每一个线程有自己的用户登录信息、用户身份信息、http请求信息,每一个线程是自己的信息。包括我们的高级框架ssh,hibernate里面Session的管理就是使用ThreadLocal,它里面有一个HibernateUtil用的就是ThreadLocal来实现的。或者我们在不同的线程里面设置bean的信息,保证每个线程的bean相互独立,这个Bean就是我们说的java的对象pojo类,存储数据用的,保证我们数据的独立。
package com.sxt.others;
/**
* ThreadLocal:每个线程自身的存储本地、局部区域
* get/set/initialValue
* @author
*
*/
public class ThreadLocalTest01 {
//默认初始值
//private static ThreadLocal<Integer> threadLocal = new ThreadLocal<> ();
//更改初始化值
/*private static ThreadLocal<Integer> threadLocal = new ThreadLocal<> () {
protected Integer initialValue() {
return 200;
};
};*/
//jdk1.8之后可以这么写
private static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(()-> 200);
public static void main(String[] args) {
//获取值
System.out.println(Thread.currentThread().getName()+"-->"+threadLocal.get());
//设置值
threadLocal.set(99);
System.out.println(Thread.currentThread().getName()+"-->"+threadLocal.get());
new Thread(new MyRun()).start();
new Thread(new MyRun()).start();
}
public static class MyRun implements Runnable{
public void run() {
threadLocal.set((int)(Math.random()*99));
System.out.println(Thread.currentThread().getName()+"-->"+threadLocal.get());
}
}
}
package com.sxt.others;
/**
* ThreadLocal:每个线程自身的数据,更改不会影响其他线程
* @author
*
*/
public class ThreadLocalTest02 {
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();
}
}
public static class MyRun implements Runnable{
public void run() {
Integer left =threadLocal.get();
System.out.println(Thread.currentThread().getName()+"得到了-->"+left);
threadLocal.set(left -1);
System.out.println(Thread.currentThread().getName()+"还剩下-->"+threadLocal.get());
}
}
}
package com.sxt.others;
/**
* ThreadLocal:分析上下文 环境 起点
* 1、构造器: 哪里调用 就属于哪里 找线程体
* 2、run方法:本线程自身的
* @author 裴新
*
*/
public class ThreadLocalTest03 {
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());
}
public void run() {
System.out.println(Thread.currentThread().getName()+"-->"+threadLocal.get());
//new Thread(new MyRunxxx()).start();
}
}
}
package com.sxt.others;
/**
* InheritableThreadLocal:继承上下文 环境的数据 ,【拷贝】一份给子线程
* @author
*
*/
public class ThreadLocalTest04 {
private static ThreadLocal<Integer> threadLocal = new InheritableThreadLocal<>();
public static void main(String[] args) {
threadLocal.set(2);
System.out.println(Thread.currentThread().getName()+"-->"+threadLocal.get());
//此线程由main线程开辟
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"-->"+threadLocal.get());
threadLocal.set(200);
System.out.println(Thread.currentThread().getName()+"-->"+threadLocal.get());
}) .start();
}
}
注:ThreadLocal就是我们每一个线程自己的局部变量的存储空间,每一个线程都有自己的一亩三分地,可以把它看成是线程本地环境。