【java并发】线程范围内共享数据

  假定现在有个公共的变量data,有不同的线程都可以去操作它,如果在不同的线程对data操作完成后再去取这个data,那末肯定会出现线程间的数据混乱问题,由于A线程在取data数据前可能B线程又对其进行了修改,下面写个程序来讲明1下该问题:

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() {

@Override
public void run() {
int temp = new Random().nextInt();
System.out.println(Thread.currentThread().getName() + " has put a data: " + temp); //打印出来为了看效果
data = temp; //操作数据:赋新值

new TestA().getData();
new TestB().getData();
}
}).start();
}
}

static class TestA {
public void getData() {
System.out.println("A get data from " + Thread.currentThread().getName() + ": " + data);//取出公共数据data
}
}

static class TestB {
public void getData() {
System.out.println("B get data from " + Thread.currentThread().getName() + ": " + data);
}
}
}

  来看1下打印出来的结果:

Thread-0 has put a data: ⑴885917900
Thread⑴ has put a data: ⑴743455464
A get data from Thread-0: ⑴743455464
A get data from Thread⑴: ⑴743455464
B get data from Thread⑴: ⑴743455464
B get data from Thread-0: ⑴743455464

  从结果中可以看出,两次对data赋的值确切不1样,但是两个线程最后打印出来的都是最后赋的那个值,说明Thread-0拿出的数据已不对了,这就是线程间同享数据带来的问题。
  固然,我们完全可使用synchronized关键字将run()方法中的几行代码给套起来,这样每一个线程各自履行完,打印出各自的信息,这是没问题的,确切可以解决上面的线程间同享数据问题。但是,这是以其他线程被阻塞为代价的,即Thread-0在履行的时候,Thread⑴就被阻塞了,必须等待Thread-0履行完了才能履行。
  那末如果我想两个线程同时跑,并且互不影响各自取出的值,该怎样办呢?这也是本文所要总结的重点,解决该问题的思想是:虽然现在都在操作公共数据data,但是不同的线程本身对这个data要保护1个副本,这个副本不是线程间所同享的,而是每一个线程所独有的,所以不同线程中所保护的data是不1样的,最后取的时候,是哪一个线程,我就从哪一个线程中取该data。
  基于上面这个思路,我再把上面的程序做1修改,以下:

public class ThreadScopeShareData {

private static int data = 0;//公共的数据
//定义1个Map以键值对的方式存储每一个线程和它对应的数据,即Thread:data
private static Map<Thread, Integer> threadData = Collections.synchronizedMap(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() {
int temp = new Random().nextInt();
System.out.println(Thread.currentThread().getName() + " has put a data: " + temp); //打印出来为了看效果
threadData.put(Thread.currentThread(), temp); //向Map中存入本线程data数据的1个副本
data = temp; //操作数据:赋新值
new TestA().getData();
new TestB().getData();
}
}).start();
}
}

static class TestA {
public void getData() {
System.out.println("A get data from " + Thread.currentThread().getName() + ": "
+ threadData.get(Thread.currentThread())); //取出各线程保护的那个副本
}
}

static class TestB {
public void getData() {
System.out.println("B get data from " + Thread.currentThread().getName() + ": "
+ threadData.get(Thread.currentThread()));
}
}
}

  上面程序中保护了1个Map,键值对分别是线程和它的数据,那末在操作data的时候,先把各自的数据保存到这个Map中,这样每一个线程保存的肯定不同,当再取的时候,根据当前线程对象作为key来取出对应的data副本,这样不同的线程之间就不会相互影响了。这个HashMap也需要包装1下,由于HashMap是非线程安全的,上面的程序中,不同的线程有对HashMap进行写操作,就有可能产生并提问题,所以也要包装1下。最后来看1下履行结果:

Thread-0 has put a data: 1817494992
Thread⑴ has put a data: ⑴189758355
A get data from Thread-0: 1817494992
B get data from Thread⑴: ⑴189758355
A get data from Thread-0: 1817494992
B get data from Thread⑴: ⑴189758355

  就是线程范围内同享数据,即同1个线程里面这个数据是同享的,线程间是不同享的。
  这让我联想到了学习数据库的时候用到的ThreadLocal,操作数据库需要connection,如果当前线程中有就拿当前线程中存的connection,否则就新建1个放到当前线程中,这样就不会出现问题,由于每一个线程本身同享了1个connection,它不是线程间同享的。这也很好理解,这个connection肯定不能同享,假定A和B用户都拿到这个connection并开启了事务,现在A开始转账了,但是钱还没转好,B转好了关闭了事务,那末A那边就出问题了。
  线程范围内同享数据的问题就总结这么多吧~
  
  相干浏览:http://blog.csdn.net/column/details/bingfa.html


—–乐于分享,共同进步!
—–更多文章请看:http://blog.csdn.net/eson_15

波比源码 – 精品源码模版分享 | www.bobi11.com
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需!
7. 如遇到加密压缩包,请使用WINRAR解压,如遇到无法解压的请联系管理员!

波比源码 » 【java并发】线程范围内共享数据

发表评论

Hi, 如果你对这款模板有疑问,可以跟我联系哦!

联系站长
赞助VIP 享更多特权,建议使用 QQ 登录
喜欢我嘛?喜欢就按“ctrl+D”收藏我吧!♡