1、线程1运行,A、B、C,3个对象访问的变量是同一个变量,3个对象在同一个线程身上被调用的时候,它们访问的数据相同。线程2,访问就不同了,是另外一个数据了。N个线程,有N个数据。
package thread.synchronizeds.share;
import java.util.Random;
/**
* 线程共享数据 同一线程,不同对象或模块进行数据共享
*/
public class ThreadScopeShareData {
private static int data = 0;
public static void main(String[] args) {
for(int i=0;i<2;i++){
new Thread(new Runnable() {
public void run() {
data=new Random().nextInt(); //设置一个随机数
System.out.println(Thread.currentThread().getName()
+" has put data "+data);
new A().get();
new B().get();
}
}).start();
}
}
// 1、模块A
static class A {
public void get() {
System.out.println("A模块 " +Thread.currentThread().getName()
+" get data "+data);
}
}
static class B {
public void get() {
System.out.println("B模块 "+Thread.currentThread().getName()
+" get data "+ data);
}
}
}
这个时候同一线程,不同模块数据并不共享。
解决:存放到Map中,每次都存储,然后模块A、B再到Map中去拿。
package thread.synchronizeds.share;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
/**
* 线程共享数据 同一线程,不同对象或模块进行数据共享
*/
public class ThreadScopeShareData {
private static int data = 0;
//5、定义一个Map,设置好一个数据的时候放到集合,用于保存。
private static Map<String, Integer> threadData=new HashMap<String, Integer>();
public static void main(String[] args) {
for(int i=0;i<2;i++){
new Thread(new Runnable() {
public void run() {
//3、设置一个随机数
int data=new Random().nextInt(); //设置一个随机数
//4、在线程中执行A、B两个模块。
System.out.println(Thread.currentThread().getName()
+" has put data "+data);
threadData.put(Thread.currentThread().getName(), data);//6、放入数据
new A().get();
new B().get();
}
}).start();
}
}
// 1、模块A
static class A {
public void get() {
//7、通过线程名称,来取数据
int data=threadData.get(Thread.currentThread().getName());
System.out.println("A模块 " +Thread.currentThread().getName()
+" get data "+data);
}
}
// 1、模块B
static class B {
public void get() {
int data=threadData.get(Thread.currentThread().getName());
System.out.println("B模块 "+Thread.currentThread().getName()
+" get data "+ data);
}
}
}
如下:通过ThreadLocal类实现线程范围共享数据
2、 ThreadLocal类及应用技巧-线程绑定
总结:一个变量,ThreadLocal只能放一个数据。
多个变量就打包、封装,使用JavaBean存放,也就是放到一个类里面.
设计线程范围共享对象技巧:
对象的实例与每个线程有关的,那么这个设计交给我自己管理,其他的用户在任意线程上调用我的方法自然的与这个线程有关的实例。
这个类设置出来就是专门与线程绑定的,在线程的任意地方,调用我的一个方法我就会得到有关线程的实例对象,这个实例对象不需要用户去创建。
如:Struts2会用到,一个请求就是一个线程,一个线程就有一个容器对象,这个容器对象就是把这个请求相关的所有的东西都装在容器里面,在这个容器这对这个请求有效,另外的就是其他的容器,另外的容器装着另外有关的东西。
/**线程范围共享数据 。同一线程,不同对象或模块进行数据共享*/
public class ThreadScopeShareData {
private static int data = 0;
//5、定义一个Map,设置好一个数据的时候放到集合,用于保存。
// private static Map<String, Integer> threadData=new HashMap<String, Integer>();
//只有一个变量采用
private static ThreadLocal<Integer> x = new ThreadLocal<Integer>();
//多个变量采用
private static ThreadLocal<MyThreadScopeData> myThreadScopeData = new ThreadLocal<MyThreadScopeData>();
public static void main(String[] args) {
for(int i=0;i<2;i++){
new Thread(new Runnable() {
public void run() {
//3、设置一个随机数
int data=new Random().nextInt(); //设置一个随机数
//4、在线程中执行A、B两个模块。
System.out.println(Thread.currentThread().getName()
+" has put data "+data);
// threadData.put(Thread.currentThread().getName(), data);//6、放入数据
x.set(data);
// MyThreadScopeData myData = new MyThreadScopeData();
// myData.setName("name" + data);
// myData.setAge(data);
// myThreadScopeData.set(myData);
/**拿到的就是本线程相关的实例对象
* 如果已经存在这个对象,就使用。
* 不存在就创建,把实例对象放到ThreadLocal里面。*/
MyThreadScopeData.getThreadInstance().setName("name "+data);
MyThreadScopeData.getThreadInstance().setAge(data);
new A().get();
new B().get();
}
}).start();
}
}
// 1、模块A
static class A {
public void get() {
//7、通过线程名称,来取数据
// int data=threadData.get(Thread.currentThread().getName());
int data = x.get();
// System.out.println("A模块 " + Thread.currentThread().getName()
// + " get data :" + data);
// MyThreadScopeData myData=myThreadScopeData.get();
MyThreadScopeData myData=MyThreadScopeData.getThreadInstance();
System.out.println("A模块 " +Thread.currentThread().getName()
+" getMyData: "+myData.getName()+","+myData.getAge());
}
}
// 1、模块B
static class B {
public void get() {
int data = x.get();
// System.out.println("B模块 " + Thread.currentThread().getName()
// + " get data :" + data);
// MyThreadScopeData myData=myThreadScopeData.get();
MyThreadScopeData myData=MyThreadScopeData.getThreadInstance();
System.out.println("B模块 " +Thread.currentThread().getName()
+" getMyData: "+myData.getName()+","+myData.getAge());
}
}
}
class MyThreadScopeData{
/**类似于单例模式,单例只有一个对象。
而这个方法采用的是N个线程N个变量*/
private MyThreadScopeData(){}
public static /**synchronized*/ MyThreadScopeData getThreadInstance() {
MyThreadScopeData instance=map.get();
//懒汉式
if(instance==null){
instance=new MyThreadScopeData();
map.set(instance);
}
return instance;
}
//恶汉式
// private static MyThreadScopeData instance=new MyThreadScopeData();
// private static MyThreadScopeData instance=null;
private static ThreadLocal<MyThreadScopeData> map=new ThreadLocal<MyThreadScopeData>();
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;
}
}