线程内共享数据ThreadLocal的使用
1、说明:
每个当前线程中都有一个ThreadLocal,这个ThreadLocal是与其他线程分开的。存储在ThreadLocal是数据,对于线程内共享是共享的,线程外(其它线程)是独立的。
2、线程内共享数据的两种场景(共享一个or多个变量)
(1)场景一:线程内只需共享一个变量
-
方法一:定义private static Map<Thread, Integer> threadData = new HashMap<Thread, Integer>();变量,存储每个线程是共享变量。
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
/**
* 线程数据共享demo(线程内共享变量,线程外独立)
*
* 方法一:定义Map<Thread, Integer>对象,存储共享数据
*/
public class ThreadScopeShareData {
private static int data = 0;
// 存储每个线程中独立的数据
private static Map<Thread, Integer> threadData = new HashMap<Thread, Integer>();
public static void main(String[] args) {
for (int i = 0; i < 2; i++) {
new Thread(new Runnable() {
@Override
public void run() {
data = new Random().nextInt();
threadData.put(Thread.currentThread(), data); // 将当前线程的线程和线程共享数据存入map中
System.out.println(Thread.currentThread().getName() + "has put data:" + data);
new A().get(); // 调用模块一的方法
new B().get(); // 调用模块二的方法
}
}).start();
}
}
// 模块一
static class A {
public void get() {
int data = threadData.get(Thread.currentThread()); // 从map中获取当前线程数据对象
System.out.println("A from " + Thread.currentThread().getName() + " get data:" + data);
}
}
// 模块二
static class B {
public void get() {
int data = threadData.get(Thread.currentThread()); // 从map中获取当前线程数据对象
System.out.println("B from " + Thread.currentThread().getName() + " get data:" + data);
}
}
}
-
方法二:使用ThreadLocal。
import java.util.Random;
/**
* 线程数据共享demo(ThreadLocal:线程内共享变量,线程外独立)
*
* 场景一:线程内只需共享一个变量
* 方法二:使用ThreadLocal
*/
public class ThreadLocalTest1 {
// 创建一个ThreadLocal对象
private static ThreadLocal<Integer> x = new ThreadLocal<Integer>();
public static void main(String[] args) {
for (int i = 0; i < 2; i++) {
new Thread(new Runnable() {
@Override
public void run() {
int data = new Random().nextInt(); // 生成当前线程的数据
System.out.println(Thread.currentThread().getName() + "has put data:" + data);
x.set(data); // 将当前线程的数据放入ThreadLocal
new A().get(); // 调用模块一的方法
new B().get(); // 调用模块二的方法
}
}).start();
}
}
// 模块一
static class A {
public void get() {
int data = x.get();// 获取当前线程的数据
System.out.println("A from " + Thread.currentThread().getName() + " get data:" + data);
}
}
// 模块二
static class B {
public void get() {
int data = x.get();// 获取当前线程的数据
System.out.println("B from " + Thread.currentThread().getName() + " get data:" + data);
}
}
}
(2)场景二:线程内需共享多个变量
-
方法一:定义一个共享数据结构的类,将共享数据结构类作为ThreadLocal的泛型
import java.util.Random;
/**
* 线程数据共享demo(ThreadLocal:线程内共享变量,线程外独立)
*
* 场景二:线程内需共享多个变量
* 方法一:定义一个共享数据结构的类,将共享数据结构类作为ThreadLocal的泛型
*/
public class ThreadLocalTest2 {
// 创建一个ThreadLocal对象,并将MyThreadScopeData1座位泛值类型
private static ThreadLocal<MyThreadScopeData1> myThreadScopeData = new ThreadLocal<MyThreadScopeData1>();
public static void main(String[] args) {
for (int i = 0; i < 2; i++) {
new Thread(new Runnable() {
@Override
public void run() {
int data = new Random().nextInt();
System.out.println(Thread.currentThread().getName() + "has put data:" + data);
// 设置当前线程的数据对象,并且将对象放置在ThreadLocal对象中
MyThreadScopeData1 myData = new MyThreadScopeData1();
myData.setName(Thread.currentThread().getName());
myData.setAge(data);
myThreadScopeData.set(myData);
new A().get();
new B().get();
}
}).start();
}
}
// 模块一
static class A {
public void get() {
MyThreadScopeData1 myData = myThreadScopeData.get(); // 获取当前线程数据对象
System.out.println("A from " + Thread.currentThread().getName() + ": getName()=" + myData.getName()
+ ", getAge()=" + myData.getAge());
}
}
// 模块二
static class B {
public void get() {
MyThreadScopeData1 myData = myThreadScopeData.get(); // 获取当前线程数据对象
System.out.println("B from " + Thread.currentThread().getName() + ": getName()=" + myData.getName()
+ ", getAge()=" + myData.getAge());
}
}
}
/**
* 定义共享数据结构类
*/
class MyThreadScopeData1 {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
-
方法二:定义一个共享数据结构的类,ThreadLocal对象放入共享数据结构的类中,在共享数据结构类中存储所有线程的共享数据
import java.util.Random;
/**
* 线程数据共享demo(ThreadLocal:线程内共享变量,线程外独立)
*
* 场景二:线程内需共享多个变量
* 方法二:定义一个共享数据结构的类,ThreadLocal对象放入共享数据结构的类中,在共享数据结构类中存储所有线程的共享数据
*/
public class ThreadLocalTest3 {
public static void main(String[] args) {
for (int i = 0; i < 2; i++) {
new Thread(new Runnable() {
@Override
public void run() {
int data = new Random().nextInt();
System.out.println(Thread.currentThread().getName() + "has put data:" + data);
// 设置当前线程的数据对象,先取出MyThreadScopeData的实例,再设置值
MyThreadScopeData.getThreadDataInstance().setName(Thread.currentThread().getName());
;
MyThreadScopeData.getThreadDataInstance().setAge(data);
new A().get(); // 调用模块一的方法
new B().get(); // 调用模块二的方法
}
}).start();
}
}
// 模块一
static class A {
public void get() {
MyThreadScopeData myData = MyThreadScopeData.getThreadDataInstance(); // 获取当前线程的共享数据对象
System.out.println("A from " + Thread.currentThread().getName() + ": getName()=" + myData.getName()
+ ", getAge()=" + myData.getAge());
}
}
// 模块二
static class B {
public void get() {
MyThreadScopeData myData = MyThreadScopeData.getThreadDataInstance(); // 获取当前线程的共享数据对象
System.out.println("B from " + Thread.currentThread().getName() + ": getName()=" + myData.getName()
+ ", getAge()=" + myData.getAge());
}
}
}
/**
* 定义共享数据结构类,类中定义ThreadLocal对象,将所有线程的共享数据都放置这个类的这个对象中
*/
class MyThreadScopeData {
private String name;
private int age;
// private static MyThreadScopeData instance = null;
private static ThreadLocal<MyThreadScopeData> map = new ThreadLocal<MyThreadScopeData>();
// 步骤1、构建私有构造函数,不允许外部通过new创建
private MyThreadScopeData() {
};
// 步骤2、开放获取实例的方法
public static MyThreadScopeData getThreadDataInstance() {
MyThreadScopeData instance = map.get();
if (null == instance) {
instance = new MyThreadScopeData();
map.set(instance);
}
return instance;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
3、总结:
在线程内需共享多个变量中推荐使用方法二,这种将ThreadLocal对象定义在共享数据结构类的方式将使代码更加优雅。