既然ThreadLocal类为每一个使用该变量的线程都提供了一个变量值的副本,使每一个线程都可以独立地改变自己的副本,而不会和其他线程的副本冲突,好像每一个线程都完全拥有该变量。那么在同一个线程内,各个模块就可以共享变量并且不会和其他线程的变量产生冲突。
例如线程1运行时会调用A、B、C三个模块\对象,这三个模块\对象会访问一个相同变量x;同样线程2运行时也会调用A、B、C三个模块\对象,这三个模块\对象也会访问一个相同变量x。如果这个变量是普通的静态变量,那么无论哪个线程的哪个模块\对象访问,都可以改变该变量的值并且在其他线程的模块\对象访问时访问到的是被改变后的值。如果将x定义为ThreadLocal类的对象,那么线程1和线程2都会保留一个变量x的副本,它们相互之间不会冲突,这样就实现了线程范围内共享变量。
见下面程序
首先定义一个数据共享类,其中count要被多个模块访问
//定义一个数据共享类,其中count要被多个模块访问
class ShareData {
//将count定义为ThreadLocal类型
//以便在线程范围内实现共享
private ThreadLocal<Integer> count = new ThreadLocal<Integer>();
public void setCount(int i){
//自动装箱
count.set(i);
}
public int getCount(){
//自动拆箱
return count.get();
}
}
public class ThreadShareData {
//创建一个ShareData对象,这个对象被两个线程使用
private static ShareData data = new ShareData();
public static void main(String[] args) {
// TODO Auto-generated method stub
//使用循环开启两个线程
for(int i = 0; i < 2; i++){
new Thread(){
public void run() {
//为ShareData的count赋值
int count = new Random().nextInt();
data.setCount(count);
System.out.println(Thread.currentThread().getName()
+ "--已为count赋值,值为" + count);
new A(data).show();
new B(data).show();
}
}.start();
}
}
//内部类模块A
static class A{
private ShareData data;
public A(ShareData data){
this.data = data;
}
//访问count
public void show(){
System.out.println("线程:" + Thread.currentThread().getName() +
"--A模块count值" + data.getCount());
}
}
//内部类模块B
static class B{
private ShareData data;
public B(ShareData data){
this.data = data;
}
//访问count
public void show(){
System.out.println("线程:" + Thread.currentThread().getName() +
"--B模块count值" + data.getCount());
}
}
}
运行
一个ThreadLocal代表一个变量,故其中只能放一个数据。如果有n个变量都要线程范围内共享,则要定义n个ThreadLocal对象,或者将n个变量封装到一个实体对象中。
使用ThreadLocal可以在线程范围内共享变量,也可以共享对象。要想在线程范围内共享对象,该类的设计与单例类有些类似。
定义一个对象共享类,在线程范围内共享对象
//定义一个对象共享类,在线程范围内共享对象
class ShareInstance {
//名称和id号
private String name;
private int id;
//使用ThreadLocal,存储线程内共享的对象
private static ThreadLocal<ShareInstance> map = new ThreadLocal<ShareInstance>();
//构造器私有化
private ShareInstance(){}
//提供静态方法获取对象
public static ShareInstance getInstance(){
ShareInstance instance = map.get();
if(instance == null){
instance = new ShareInstance();
map.set(instance);
}
return instance;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
在 ThreadShareInstance类中开启两个线程,每个线程都有两个内部类使用ShareInstance对象
public class ThreadShareInstance {
public static void main(String[] args) {
// TODO Auto-generated method stub
//使用循环开启两个线程
for(int i = 0; i < 2; i++){
new Thread(){
public void run() {
ShareInstance instance = ShareInstance.getInstance();
//为ShareInstance的name和id赋值
int id = new Random().nextInt();
instance.setName("name");
instance.setId(id);
System.out.println(Thread.currentThread().getName()
+ "--已为id赋值,值为" + id);
new A().show();
new B().show();
}
}.start();
}
}
//内部类模块A
static class A{
//访问instance
public void show(){
ShareInstance instance = ShareInstance.getInstance();
System.out.println("线程:" + Thread.currentThread().getName() +
"--A模块name值为:" + instance.getName() + ",id值为:" + instance.getId());
}
}
//内部类模块B
static class B{
//访问instance
public void show(){
ShareInstance instance = ShareInstance.getInstance();
System.out.println("线程:" + Thread.currentThread().getName() +
"--B模块name值为:" + instance.getName() + ",id值为:" + instance.getId());
}
}
}
运行程序
三个模块:内部类A和B,主方法中都有一个ShareInstance对象,在同一个线程中,他们是同一个对象;而不同线程中是不同对象。
通过使用ThreadLocal设计ShareInstance类,就可以在线程范围内共享对象而在不同线程中使用不同对象。