java线程中的一个小问题_JAVA_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > JAVA > java线程中的一个小问题

java线程中的一个小问题

 2014/9/22 18:26:59  Paper_Gou  程序员俱乐部  我要评论(0)
  • 摘要:有下面两个类:packageDemo;importjava.util.HashMap;publicclassHashMapTest{privateHashMap<String,Integer>map=newHashMap<String,Integer>();publicsynchronizedvoidadd(Stringkey){Integervalue=map.get(key);System.out.println("object1--------"+value)
  • 标签:

?

?有下面两个类:

class="java">package Demo;

import java.util.HashMap;

public class HashMapTest{
	
	private HashMap<String, Integer> map = 
			new HashMap<String, Integer>();
	
	public synchronized void add(String key){
		Integer value = map.get(key);
		System.out.println("object1 -------- " +value);
		if(value == null){
			map.put(key, 1);
		}else{
			map.put(key, value+1);
		}
	}
	
}

?

package Demo;

import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentHashMapTest {
	private ConcurrentHashMap<String, Integer> map = 
			new ConcurrentHashMap<String, Integer>();
	public void add(String key){
		Integer value = map.get(key);
		System.out.println("object2 -------- " + value);
		if(value == null){
			map.put(key, 1);
		}else{
			map.put(key, value+1);
		}
	}
}

?两个都类中都有一个map容器对象,第一个类中容器为线程不安全的HashMap对象,第二类中为线程安全的ConcurrentHashMap 对象。同样的也都有一个添加计数方法add,第一个类中是加了锁synchronized,第二个中直接访问。

?

两个类都是希望自己的数据容器map能够在多线程的访问的情况下正常存取。

第一种使用了线程不安全容器加锁的方式实现,第二种直接使用了线程安全容器进行访问。

下面是测试代码:

package Demo;

public class ComputeObject implements Runnable{
	
	public static HashMapTest hashMapTest = new HashMapTest();
	public static ConcurrentHashMapTest concurrentHashMapTest = new ConcurrentHashMapTest();
	
	public static void main(String[] args) {
		for (int i = 0; i < 10; i++) {
			new Thread(new ComputeObject()).start();
		}
	}

	@Override
	public void run() {
		hashMapTest.add("key");
		concurrentHashMapTest.add("key");
	}
}

?主线程中开了10条子线程对两个容器进行访问。

理想结果是:两个容器除去第一次为空外,他们的中的属性key值应当为9.

object1 -------- null
object2 -------- null
object1 -------- 1
object2 -------- 1
object1 -------- 2
object2 -------- 2
object1 -------- 3
object1 -------- 4
object2 -------- 3
object1 -------- 5
object2 -------- 4
object1 -------- 6
object2 -------- 5
object1 -------- 7
object2 -------- 5
object1 -------- 8
object2 -------- 6
object2 -------- 6
object1 -------- 9
object2 -------- 7

?可以看到,类一成功实现了多线程下的数据安全访问,然而类二中出现了大量的重复数据输出。

??

?当时我们将类二中的add方法同样加上synchronized方法,输出两个输出都变为9。

?

这是因为对于ConcurrentHashMap中,它只对put,remove操作使用了同步操作,get操作并不影响,这就可能在每次读入的时候,读入了相同的数据实现了重复的增加。

所以在使用ConcurrentHashMap时,应当保证足够的小心。

jdkAPI:

获取操作(包括?get)通常不会受阻塞,因此,可能与更新操作交迭(包括?put?和?remove)。获取会影响最近完成的?更新操作的结果。对于一些聚合操作,比如?putAll?和?clear,并发获取可能只影响某些条目的插入和移除。类似地,在创建迭代器/枚举时或自此之后,Iterators 和 Enumerations 返回在某一时间点上影响哈希表状态的元素。它们不会?抛出?ConcurrentModificationException。不过,迭代器被设计成每次仅由一个线程使用。

  • 相关文章
发表评论
用户名: 匿名