一,线程局部变量ThreadLocal的作用
用于实现线程内部的数据共享,既对于相同的程序代码,多个模块在同一个线程中运行时要共享一份数据,在另一个线程访问的时候,访问的由是另一份数据。
每个线程调用ThreadLocal对象的set方法时,就相当于向内部Map集合中增加一条记录。
Map(key,value)key相当于当前的线程,value相当于set()传递进来的值。
ThreadLocal<T> threadLocal =new ThreadLocal<T>(); T是set()方法传进来的值类型。
问题:一个ThreadLocal中只能存放一个变量,既其中只能存放一个数据,如果由两个数据,可以定义两个ThreadLocal,但是如果有多个呢?例如100个?
解决方法是定义一个对象来存放这100个数据,然后在ThreadLocal中存放这个对象。
二,在 Runnable 中创建 ThreadLocal
①、在多线程的类(如 ThreadDemo 类)中,创建一个 ThreadLocal 对象 threadXxx,用来保存线程间需要隔离处理的对象 xxx。
②、在 ThreadDemo 类中,创建一个获取要隔离访问的数据的方法 getXxx(),在方法中判断,若ThreadLocal 对象为 null 时候,应该 new()一个隔离访问类型的对象,并强制转换为要应用的类型
③、在 ThreadDemo 类的 run()方法中,通过调用 getXxx()方法获取要操作的数据,这样可以保证每个线程对应一个数据对象,在任何时刻都操作的是这个对象。
代码:
package com.itheima.gan;
import java.util.Random;
public class ThreadLocalTest implements Runnable{
//创建一个线程局部变量
ThreadLocal<Student> studentThreadLocal=new ThreadLocal<Student>();
@Override
public void run() {
//获取当前线程的名字
String currentThreadName=Thread.currentThread().getName();
System.out.println(currentThreadName+" is running ....");
//随机生成一个整数
Random random=new Random();
int age=random.nextInt(100);
System.out.println(currentThreadName+" is set age:"+age);
//通过这个方法为每一个线程都设置一个独立的student对象
Student student=getStudent();
student.setAge(age);
System.out.println(currentThreadName+" is first get age:"+student.getAge());
//线程沉睡
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
//线程第二次获取年纪
System.out.println(currentThreadName+" is second get age:"+student.getAge());
}
private Student getStudent() {
//先获取studnet对象
Student student=studentThreadLocal.get();
//判断对象是否为空,是空的话表示没有给局部变量设置,如果是空的话就在给局部变量重新设置一个值
if(student==null) {
student=new Student();
studentThreadLocal.set(student);
}
return student;
}
public static void main(String[] args) {
ThreadLocalTest test=new ThreadLocalTest();
Thread t1=new Thread(test,"线程1");
Thread t2=new Thread(test,"线程2");
t1.start();
t2.start();
}
}
class Student{
int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age=age;
}
}
运行结果:
