考虑一个场景:A转账给B ,我们会有账户A和账户B 两个对象,调用账户A的转出方法,调用B的转入方法,但是这两个方法要在同一事务中完成,如果有错误则回调,这两个对象方法使用同一个数据库连接,其它事务也会共享这个数据库连接,但是它们在各自的事务中有自己的数据库连接数据,互不影响。这就相当于同一个线程中调用两个模块的方法,它们的数据应该是一致的,而且与其它线程互不影响。
即我们的目的是;多个业务模块针对同一个static变量的操作 要保证在不同线程中 各模块操作的是自身对应的变量对象
package com.effort.thread;
import java.util.Random;
public class ThreadShareData {
private static int data = 0 ;
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();
System.out.println(Thread.currentThread().getName()+ " put random data:"+data);
new A().get() ;
new B().get() ;
}
}).start() ;
}
}
static class A {
public int get(){
System.out.println("A from " + Thread.currentThread().getName()
+ " get data :" + data);
return data ;
}
}
static class B{
public int get(){
System.out.println("B from " + Thread.currentThread().getName()
+ " get data :" + data);
return data ;
}
}
}
模块A ,B都需要访问static的变量data 在线程0中会随机生成一个data值 假设为10 那么此时模块A和模块B在线程0中得到的data的值为10 ;在线程1中 假设会为data赋值为20 那么在当前线程下
模块A和模块B得到data的值应该为20
看程序执行的结果:
Thread-0 put random data:-1344602819
Thread-1 put random data:-1842611697
A from Thread-1 get data :-1842611697
A from Thread-0 get data :-1842611697
B from Thread-1 get data :-1842611697
B from Thread-0 get data :-1842611697
在线程0中执行模块A和模块B的方法去获取data的值 但是在获取之前 线程1就将data的值给修改为-1842611697 导致线程0中的模块A和模块B获取了错误的数据.
那么如何得到正确的效果呢?
可以将data数据和当前允许的线程绑定在一块,在模块A和模块B去获取数据data的时候 是通过当前所属的线程去取得data的结果就行了。
声明一个Map集合 集合的Key为Thread 存储当前所属线程 Value 保存data的值,代码如下:
package com.effort.thread;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
public class ThreadShareData {
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() {
synchronized (ThreadShareData.class) { //保证下面的代码都执行完才允许其他线程进入
data = new Random().nextInt();
threadData.put(Thread.currentThread(), data) ; //将数据绑定到带当前线程
System.out.println(Thread.currentThread().getName()+ " put random data:"+data);
new A().get() ;
new B().get() ;
}
}
}).start() ;
}
}
static class A {
public int get(){
//取数据都从当前线程中取得
int d = threadData.get(Thread.currentThread()) ;
System.out.println("A from " + Thread.currentThread().getName()
+ " get data :" + d);
return data ;
}
}
static class B{
public int get(){
//取数据都从当前线程中取得
int d = threadData.get(Thread.currentThread()) ;
System.out.println("B from " + Thread.currentThread().getName()
+ " get data :" + d);
return data ;
}
}
}
程序执行结果:
Thread-0 put random data:-1842492021
A from Thread-0 get data :-1842492021
B from Thread-0 get data :-1842492021
Thread-1 put random data:-1886142929
A from Thread-1 get data :-1886142929
B from Thread-1 get data :-1886142929
达到效果。
下一节学习ThreadLocal的基本使用。