java线程不可以共享数据,【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 threadData = Collections.synchronizedMap(new HashMap());

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值