线程范围内的共享变量
1. 线程范围内的共享变量的概念
假设有2个线程,一个全局变量 int data。2个线程内的代码共用这一个变量的声明(data),但它们操作data时,data的值在这2个线程里是独立的,互不影响的。我们这里所说的互不影响,不是我们之前说的syncronized,(线程1先修改data值,读取data值,释放锁后,线程2才可修改data和读取data,这样的话data最终的值还会变为线程2最后修改的值)。我们现在要实现的是,线程1修改了data=1, 线程2也修改了同一个data变量的值为2,data=2,最后线程1回过头再去读取时,读取出的data应该是1(它自己当时放的值就是1),线程2回头再去读取data时,读取的也是它自己的值,2. 这个data是2个线程的共享变量,但它的值在2个线程范围内各自是独立的。如下图所示:
2. 代码实现
2.1 定义全局变量
我们定义如下全局变量:
private static Map<Thread, Integer> threadData = new HashMap<Thread, Integer>();
一个map, 其中的key为正在执行的线程对象,value就是我们在上面1中所说的data变量(整数)。
在线程1和线程2的代码中会使用到这个全局变量threadData,通过不同的key来区分线程,从而获取到对应线程中所操作的data变量。
其本质是利用了Map(key,value)这个数据结构,实现了共享变量。那么这里的共享变量应该是Map还是Map里的value(整数)呢?从共享变量的角度来讲是这个MAP,因为我们2个线程内的代码都使用了同一个变量声明threadData, 但是从数据在线程内独立的角度来讲,我们其实是想让MAP中的value,这个核心数据的值在2个线程内是独立的。 所以,我们还是看核心数据,我认为共享变量应是Map里存储的那个value。
2.2 编写2个线程
开启2个线程,存储一个data变量的值到 MAP中的value里,到时候读取的时候,以MAP中的key来区分,读取对应线程中 曾经存储过的那个data变量的值。
-
package testFuture;
-
-
import java.util.HashMap;
-
import java.util.Map;
-
import java.util.Random;
-
-
public class ThreadShareData {
-
-
private static Map<Thread, Integer> threadShareData = new HashMap<Thread, Integer>();
-
public static void main(String[] args) {
-
for(int i=0;i<2;i++){
-
final int temp = i;
-
new Thread(new Runnable(){
-
@Override
-
public void run() {
-
int data = temp;
-
System.out.println(Thread.currentThread().getName()
-
+ " has modify data :" + data);
-
threadShareData.put(Thread.currentThread(), data);
-
new DataReadA().get();
-
-
}
-
}).start();
-
}
-
}
-
-
static class DataReadA{
-
public void get(){
-
int data = threadShareData.get(Thread.currentThread());
-
System.out.println("DataReadA " + Thread.currentThread().getName()
-
+ " get data :" + data);
-
}
-
}
-
-
-
}
运行日志如下:
Thread-1 has modify data :1
Thread-0 has modify data :0
DataReadA Thread-1 get data :1
DataReadA Thread-0 get data :0
我们使用for循环创建了2个线程,每一个线程里的run函数将 for循环的索引值作为data变量的值存储在了threadShareData这个map里,同时这个map中的key为当前线程对象:Thread.currentThread()。
这样我们在调用DataReadA对象的get函数时,获取的是每一个线程对应的value,即刚才存储的data变量值。在这里我们可以把DataReadA对象看作是一个程序模块。
那我们再创建一个模块,DataReadB,看看我们的运行结果。代码和运行日志如下,
代码:
-
package testFuture;
-
-
import java.util.HashMap;
-
import java.util.Map;
-
import java.util.Random;
-
-
public class ThreadShareData {
-
-
private static Map<Thread, Integer> threadShareData = new HashMap<Thread, Integer>();
-
public static void main(String[] args) {
-
for(int i=0;i<2;i++){
-
final int temp = i;
-
new Thread(new Runnable(){
-
@Override
-
public void run() {
-
int data = temp;
-
System.out.println(Thread.currentThread().getName()
-
+ " has modify data :" + data);
-
threadShareData.put(Thread.currentThread(), data);
-
new DataReadA().get();
-
new DataReadB().get();
-
}
-
}).start();
-
}
-
}
-
-
static class DataReadA{
-
public void get(){
-
int data = threadShareData.get(Thread.currentThread());
-
System.out.println("DataReadA " + Thread.currentThread().getName()
-
+ " get data :" + data);
-
}
-
}
-
-
static class DataReadB{
-
public void get(){
-
int data = threadShareData.get(Thread.currentThread());
-
System.out.println("DataReadB " + Thread.currentThread().getName()
-
+ " get data :" + data);
-
}
-
}
-
}
日志:
Thread-0 has modify data :0
Thread-1 has modify data :1
DataReadA Thread-1 get data :1
DataReadA Thread-0 get data :0
DataReadB Thread-0 get data :0
DataReadB Thread-1 get data :1
我们发现只要是在第一个线程(Thread0)里,无论是DataReadA 还是DataReadB调用get函数,读取出来的变量值都是0,因为它当时放的就是0(日志:Thread-0 has modify data :0)。同理,
Thread-1读出来的值也是它当时存储的那个变量data,如上述日志:DataReadA Thread-1 get data :1; DataReadB Thread-1 get data :1。
总结:
好了,今天线程范围内共享同一个变量声明就讲到这里,记住两点就行:1. 共享同一个变量声明; 2. 两个线程内要使用的核心数据的值,是两份,修改和读取都互不干扰。
文章来源: blog.csdn.net,作者:冉航--小虾米,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/gaoxiaoweiandy/article/details/122635736
- 点赞
- 收藏
- 关注作者
评论(0)