`
cloudeagle_bupt
  • 浏览: 541179 次
文章分类
社区版块
存档分类
最新评论

关于ConcurrencyHashmap的并发问题

阅读更多
看这段代码
package concurrencyTest;

import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;

public class ConcurrencyTest2 {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		ConcurrentHashMap<Integer, Integer>  map = new ConcurrentHashMap<Integer, Integer>() ;
		for(int i=500;i<600 ; i++)
			map.put(i, i+111111) ;
		
		long start = System.currentTimeMillis() ;
		Thread t1 = new Thread(new Producer(map)) ;
		Thread t2 = new Thread(new Consumer(map)) ;
		
		t1.start(); 
		t2.start();
		
		try {
			t1.join() ;
			t2.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("Read last : " + (System.currentTimeMillis() - start) + " ms" + " shareMap : " + map.size());
	}
}

class Producer implements Runnable {
	ConcurrentHashMap<Integer, Integer>  sharemap ;
    int num = 0 ;
	
	public Producer(ConcurrentHashMap<Integer, Integer> map) {
		sharemap = map ;
	}
	
	@Override
	public void run() {
		 int i =0 ;
		 while(i<10) {
			 add(i) ;
			 i++ ;
		 }
		 System.out.println(Thread.currentThread().getName() + " add " + 10 + " elements! ShareMap size: " + sharemap.size() );
	}

	  public void add(int item) {  //该方法线程不安全
		  if(!sharemap.containsKey(item)) {
			  sharemap.putIfAbsent(item, item + 111111) ;
		  } else {
			  sharemap.put(item, sharemap.get(item) + 111111) ; 
		  }
	  }
}

class Consumer implements Runnable {
	ConcurrentHashMap<Integer, Integer>  sharemap ;
    int num = 0 ;
	
	public Consumer(ConcurrentHashMap<Integer, Integer> map) {
		sharemap = map ;
	}
	
	@Override
	public void run() {
		 it = sharemap.values().iterator();
		 Integer i = poll(); 
		 while(i!=null) {
			 i = poll() ;
			 num++ ;
		 }
		 System.out.println(Thread.currentThread().getName() + " poll " + num + " elements! ShareMap size: " + sharemap.size() );
	}
	
	Iterator<Integer> it;

	public Integer poll() {
		     if (sharemap.size() > 0 && it!=null && it.hasNext()) {
		         Integer m = it.next();
		         it.remove();
		         return m;
		       } else {
		         return null;
		       }
	}
}

Thread-0 add 10 elements! ShareMap size: 110
Thread-1 poll 110 elements! ShareMap size: 0
Read last : 0 ms shareMap : 0

可见ConcurrencyHashMap支持并发增加和删除,且最终读取的结果没有遗漏。


但并发删除就要慎重了!

有时会报IllegelState问题,通常是两个并发删除使用了同一个iterator,导致线程并发问题。

如下面这段代码:

package concurrencyTest;

import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;

public class ConcurrencyTest3 {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		ConcurrentHashMap<Integer, Integer>  map = new ConcurrentHashMap<Integer, Integer>() ;
		for(int i=0;i<100 ; i++)
			map.put(i, i+111111) ;
		
		long start = System.currentTimeMillis() ;
		Iterator<Integer> it = map.values().iterator();
		Thread t1 = new Thread(new Consumer2(map,it)) ;
		Thread t2 = new Thread(new Consumer2(map,it)) ;
		
		t1.start(); 
		t2.start();
		
		try {
			t1.join() ;
			t2.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("Read last : " + (System.currentTimeMillis() - start) + " ms" + " shareMap : " + map.size());
	}
}

class Consumer2 implements Runnable {
	ConcurrentHashMap<Integer, Integer>  sharemap ;
	Iterator<Integer>  it ;
    int num = 0 ;
	
	public Consumer2(ConcurrentHashMap<Integer, Integer> map, Iterator<Integer> iterator) {
		sharemap = map ;
		it = iterator ;
	}
	
	@Override
	public void run() {
		 Integer i = poll(); 
		 while(i!=null) {
			 i = poll() ;
			 num++ ;
		 }
		 System.out.println(Thread.currentThread().getName() + " poll " + num + " elements! ShareMap size: " + sharemap.size() );
	}
	

	public Integer poll() {
		     if (sharemap.size() > 0 && it!=null && it.hasNext()) {
		         Integer m = it.next();
		         it.remove();
		         return m;
		       } else {
		         return null;
		       }
	}
}

两个并发线程用一个iterator,直接报:

Exception in thread "Thread-0" Thread-1 poll 78 elements! ShareMap size: 1
java.lang.IllegalStateException
	at java.util.concurrent.ConcurrentHashMap$HashIterator.remove(ConcurrentHashMap.java:1365)
	at concurrencyTest.Consumer2.poll(ConcurrencyTest3.java:58)
	at concurrencyTest.Consumer2.run(ConcurrencyTest3.java:48)
	at java.lang.Thread.run(Thread.java:722)
Read last : 2 ms shareMap : 1



即使是使用两个各自的iterator线程,也是不安全的,因为可能造成重复读取,两边读到的数据量并不一致!

参考这篇文章:http://blog.csdn.net/cloudeagle_bupt/article/details/52643535

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics