ThreadLocal是一个本地线程副本变量工具类。主要用于将私有线程和该线程存放的副本对象做一个映射,各个线程之间的变量互不干扰,在高并发场景下,可以实现无状态的调用,特别适用于各个线程依赖不同的变量值完成操作的场景。
package cn.fg.demo;
public class ThreadLocalTest implements Runnable {
private ThreadLocal<String> threadLocal = new ThreadLocal<>();
private String name;
@Override
public void run() {
name = Thread.currentThread().getName(); //将当前线程名字赋给name
threadLocal.set(name); //threadLocal 使用threadLocal set name
try {
Thread.sleep(1000); //使当前前程停止1秒,以便观察结果
} catch (InterruptedException e) {}
System.out.println(Thread.currentThread().getName() + ":" + threadLocal.get()); //输出结果
}
public static void main(String[] args) {
//开启10个并发线程
ThreadLocalTest test = new ThreadLocalTest();
for (int i = 0; i < 10; i++) {
new Thread(test,"thread" + i).start();
}
}
}
输出结果:每个线程得到的name值都是不一样的。
如果修改代码为
name = Thread.currentThread().getName(); //将当前线程名字赋给name
//threadLocal.set(name); //threadLocal 使用threadLocal set name
try {
Thread.sleep(1000); //使当前前程停止1秒,以便观察结果
} catch (InterruptedException e) {}
System.out.println(Thread.currentThread().getName() + ":" + name);
其结果为:name的值都被最后thread9给覆盖了,出现了线程安全问题
package cn.fg.demo;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* ThreadLocal 应用举例
* 我们知道SimpleDateFormat是有线程安全问题的,不能用作全局变量
* 但是使用了ThreadLocal后,就可以用作全局变量使用了
*/
public class ThreadLocalTest implements Runnable {
private ThreadLocal<SimpleDateFormat> threadLocal = new ThreadLocal<SimpleDateFormat>(){
//重写ThreadLocal.initialValue方法
@Override
protected SimpleDateFormat initialValue() {
return new SimpleDateFormat("yyyy-MM-dd"); //返回一个SimpleDateFormat对象,ThreadLocal的initialValue方法默认是返回null
}
};
@Override
public void run() {
//在没有threadLocal.set()前,或threadLocal.remove()后,使用threadLocal.get()会得到threadLocal.initialValue的返回值
//这里的返回值就是SimpleDateFormat对象
System.out.println(threadLocal.get().format(new Date())); //输出当前格式化后的日期
}
public static void main(String[] args) {
//开启10个并发线程
ThreadLocalTest test = new ThreadLocalTest();
for (int i = 0; i < 10; i++) {
new Thread(test,"thread" + i).start();
}
}
}