线程范围内的共享变量

网友投稿 548 2022-05-29

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 threadData = new HashMap();

一个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 threadShareData = new HashMap();

线程范围内的共享变量

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 threadShareData = new HashMap();

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.  两个线程内要使用的核心数据的值,是两份,修改和读取都互不干扰。

任务调度

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Java 9 的十大新特性
下一篇:【数据库事务与锁机制】- 事务隔离的实现
相关文章