线程范围内的共享变量

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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冉航--小虾米

希望得到您的鼓励和交流

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值