java 多线程系列文章列表, 请查看目录: 《java 多线程学习笔记》
在多线程开发中, 我们有时需要用到一些和线程状态相关的变量, 每个线程所拥有的变量不一致. java 提供了ThreadLocal 变量来实现.
1. ThreadLocal
ThreadLocal 为每一个使用该变量的线程创建了一个副本, 使得每一个线程都可以独立地变更自己的副本, 与其它线程的副本隔离, 以实现线程对象的私有变量.
1.1 ThreadLocal API
方法签名 | 方法描述 |
---|---|
public void set(T value) | 设置当前线程中的变量值 |
public T get() | 获取当前线程中的变量值 |
public void remove() | 删除当前线程中的变量值 |
1.2 ThreadLocal 与线程同步区别
ThreadLocal 和线程同步(synchronized, Lock, AutomicXXX) 其实是两回事儿, 所针对的问题是不一致的. 很多人会混淆, 面试的时候也会被问到, 因此笔者拿出来单独讨论一下.
- 线程同步: 线程同步目的让多线程对共享变量按顺序操作, 但是操作的同一份数据, 多线程之间相互影响.
- ThreadLocal: 目的是让多线程对共享变量独立操作, 操作的是各自的副本数据, 多线程之间互不影响.
2. ThreadLocal 用法示例
2.1 业务类
- 使用ThreadLocal 作为私有属性, 在声明变量时, 直接初始化
public class User {
private ThreadLocal<String> nameLocal = new ThreadLocal<>();
public String getName() {
return nameLocal.get();
}
public void setName(String name) {
System.out.println("set name:" + name);
this.nameLocal.set(name);
}
}
2.2 测试类
- 创建一个线程共享对象user
- 线程中休眠一下, 再调用getName, 否则可能看不出效果
public static void main(String[] args) {
// 1. 创建一个共享对象
User user = new User();
// 2. 创建两个线程
new Thread() {
@Override
public void run() {
user.setName("zhangsan");
ThreadUtil.sleep(3);
System.out.println("zhangsan getName:" + user.getName());
}
}.start();
new Thread() {
@Override
public void run() {
user.setName("lisi");
ThreadUtil.sleep(3);
System.out.println("lisi getName:" + user.getName());
}
}.start();
}
2.3 测试输出
从结果上来看, 两个线程都对同一个user对象的name属性进行了修改, 但是两个线程获得的均是自己设置的值.
set name:zhangsan
set name:lisi
zhangsan getName:zhangsan
lisi getName:lisi