问题:实现线程范围内的数据共享,即每个线程只能访问它自己的数据,不能访问其他线程的数据。具体逻辑如下图所示:
1.方法一:使用Map<线程Thread,数据类型DataType>
使用Map<线程Thread,数据类型DataType>,其中key为Thread,即线程;value为DataType,即要线程范围内共享的数据的数据类型。这样就可以通过线程来获取其相应的数据。案例如下:
package com.lesson5;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
/*
* 问题:实现线程范围内的数据共享
*/
public class ThreadScopeShareData {
//ThreadLocal就相当于Map<Thread,Integer>
private static Map<Thread,Integer> threadData=new HashMap<Thread,Integer>();
public static void main(String[] args){
for(int i=0;i<2;i++){
Runnable r = new Runnable() {
@Override
public void run() {
int data = new Random().nextInt();
threadData.put(Thread.currentThread(), data);
System.out.println(Thread.currentThread().getName()+ " put data: " + threadData.get(Thread.currentThread()));
new A().get();
new B().get();
}
};
Thread t = new Thread(r);
t.start();
}
}
static class A{
public void get(){
System.out.println("A from "+Thread.currentThread().getName()+" get data:"+threadData.get(Thread.currentThread()));
}
}
static class B{
public void get(){
System.out.println("B from "+Thread.currentThread().getName()+" get data:"+threadData.get(Thread.currentThread()));
}
}
}
运行结果如下:
2.方法二:使用ThreadLocal
ThreadLocal的作用和目的:用于实现线程内的数据共享,即对于相同的程序代码,多个模块在同一线程中运行时要共享一份数据,而在另外线程中运行时又共享另外一份数据。每个线程调用全局ThreadLocal对象的set方法,就相当于在其内部的map中增加一条记录,key分别是各自的线程,value是各自的set方法传进去的值。在线程结束时可以调用ThreadLocal.clear()方法,这样会更快释放内存,不调用也可以,因为线程结束后也可以自动释放相关的ThreadLocal变量。案例如下:
package com.lesson5;
import java.util.Random;
/*
* 问题:使用ThreadLocal实现线程范围内的数据共享
*/
public class ThreadLocalShareData {
//定义一个全局的ThreadLocal变量
static ThreadLocal<Integer> x=new ThreadLocal<Integer>();
public static void main(String[] args){
//启动多个线程向ThreadLocal变量中存储一个随机值
for(int i=0;i<2;i++){
Runnable r = new Runnable() {
@Override
public void run() {
int data = new Random().nextInt();
x.set(data);
System.out.println(Thread.currentThread().getName()+ " put data: " + data);
//各个线程调用其他多个类的方法读取ThreadLocal变量中的值,可以看到多个类在同一个线程中共享同一份数据
new A().get();
new B().get();
}
};
Thread t = new Thread(r);
t.start();
}
}
static class A{
public void get(){
System.out.println("A from "+Thread.currentThread().getName()+" get data:"+x.get());
}
}
static class B{
public void get(){
System.out.println("B from "+Thread.currentThread().getName()+" get data:"+x.get());
}
}
}
3.封装ThreadLocal,封装线程共享变量
package com.lesson5;
import java.util.Random;
/*
* 问题:一个ThreadLocal的value代表一个变量,故其中只能存放一个数据,当有两个变量都要线程范围内共享呢?一个简单
* 的方法是定义两个ThreadLocal对象,但如果有100个变量要线程共享又该怎么办呢?
* 改进:实现对ThreadLocal变量的封装,让外界不直接操作ThreadLocal变量。对对象类型的数据的封装,比较常见,
* 即,让某个类针对不同线程分别创建不同的实例对象。上述问题的解决方法是,先定义一个对象来疯转这100个变量,然后再在
* ThreadLocal中存储这一对象。
*
*/
public class ThreadLocalShareData2 {
public static void main(String[] args){
for(int i=0;i<2;i++){
Runnable r = new Runnable() {
@Override
public void run() {
int data = new Random().nextInt();
MyThreadScopeData myThreadScopeData=MyThreadScopeData.getThreadInstance();
myThreadScopeData.setName("itsname"+data);
myThreadScopeData.setAge(data);
System.out.println(Thread.currentThread().getName()+ " put data: " + data);
new A().get();
new B().get();
}
};
Thread t = new Thread(r);
t.start();
}
}
static class A{
public void get(){
MyThreadScopeData myThreadScopeData=MyThreadScopeData.getThreadInstance();
System.out.println("A from "+Thread.currentThread().getName()+" get data: name="+myThreadScopeData.getName()+" age="+myThreadScopeData.getAge());
}
}
static class B{
public void get(){
MyThreadScopeData myThreadScopeData=MyThreadScopeData.getThreadInstance();
System.out.println("B from "+Thread.currentThread().getName()+" get data: name="+myThreadScopeData.getName()+" age="+myThreadScopeData.getAge());
}
}
}
class MyThreadScopeData{
//封装的变量,可以封装任意多个
private String name;
private int age;
//饿汉式单例
private static ThreadLocal<MyThreadScopeData> threadLocalMap=new ThreadLocal<MyThreadScopeData>();
//封装ThreadLocal对象,向外提供获取相应线程共享数据的接口
public static MyThreadScopeData getThreadInstance(){
MyThreadScopeData instance=threadLocalMap.get();
if(instance==null){
instance=new MyThreadScopeData();
threadLocalMap.set(instance);
}
return instance;
}
//懒汉式单例
/*private static ThreadLocal<MyThreadScopeData> threadLocalMap=null;
//封装ThreadLocal对象,向外提供获取相应线程共享数据的接口
public static MyThreadScopeData getThreadInstance(){
synchronized(MyThreadScopeData.class){
if(threadLocalMap==null){
System.out.println("执行一次......");
threadLocalMap=new ThreadLocal<MyThreadScopeData>();
}
}
//instance不是所有线程共享的数据,因此不需要同步
MyThreadScopeData instance=threadLocalMap.get();
if(instance==null){
instance=new MyThreadScopeData();
threadLocalMap.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;
}
}
运行结果如下: