在ConcurrentHashMap中,使用了分段锁机制,所以任意数量的读线程可以并发访问Map、读操作和写操作的线程可以并发访问Map、并且一定数量(默认是使用16个锁)的写线程也可以并发修改Map。ConcurrentHashMap提供的迭代器不会抛出ConcurrentModificationExeption,而且具有弱一致性,它可以容忍并发的修改。当创建迭代器时会遍历已有的元素,并可以(但是不保证)在迭代器被构造后将修改操作反映给容器。就是迭代器创建完成后,其他线程对map的修改,对遍历线程没有影响
那么,当多个线程同时迭代一个ConcurrentHashMap的时候会发生什么呢?在遍历的时候更新又会发生什么呢?
1,多个线程可以同时迭代ConcurrentHashMap;
2,ConcurrentHashMap保证遍历的时候更新元素不会break(这正是并发容器的意义所在),但是不能保证数据的一致性,而迭代器保证的是:它反映的是创建迭代器时容器的状态。
注意:
从ConcurrentHashMap那里得到的iterator是为单线程设计的,即不可以传递它们,每一个线程都必须有自己的iterator。
例子:
(1)两个读线程和一个修改线程,每个线程各自拥有一个Iterator,并发访问ConcurrentHashMap。
import java.util.Map;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ConcurrentMapIteration
{
private final Map<String, String> map = new ConcurrentHashMap<String, String>();
private final static int MAP_SIZE = 100000;
public static void main(String[] args)
{
new ConcurrentMapIteration().run();
}
public ConcurrentMapIteration()
{
for (int i = 0; i < MAP_SIZE; i++)
{
map.put("key" + i, UUID.randomUUID().toString());
}
}
private final ExecutorService executor = Executors.newCachedThreadPool();
private final class Accessor implements Runnable
{
private final Map<String, String> map;
public Accessor(Map<String, String> map)
{
this.map = map;
}
@Override
public void run()
{
for (Map.Entry<String, String> entry : this.map.entrySet())
{
System.out.println(
Thread.currentThread().getName() + " - [" + entry.getKey() + ", " + entry.getValue() + ']'
);
}
}
}
private final class Mutator implements Runnable
{
private final Map<String, String> map;
private final Random random = new Random();
public Mutator(Map<String, String> map)
{
this.map = map;
}
@Override
public void run()
{
for (int i = 0; i < 100; i++)
{
this.map.remove("key" + random.nextInt(MAP_SIZE));
this.map.put("key" + random.nextInt(MAP_SIZE), UUID.randomUUID().toString());
System.out.println(Thread.currentThread().getName() + ": " + i);
}
}
}
private void run()
{
Accessor a1 = new Accessor(this.map);
Accessor a2 = new Accessor(this.map);
Mutator m = new Mutator(this.map);
executor.execute(a1);
executor.execute(m);
executor.execute(a2);
}
}
结果:正常运行
两个读线程共享一个Iterator
import java.util.Iterator;
import java.util.Map;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ConcurrentMapIteration
{
private final Map<String, String> map = new ConcurrentHashMap<String, String>();
private final Iterator<Map.Entry<String, String>> iterator;
private final static int MAP_SIZE = 100000;
public static void main(String[] args)
{
new ConcurrentMapIteration().run();
}
public ConcurrentMapIteration()
{
for (int i = 0; i < MAP_SIZE; i++)
{
map.put("key" + i, UUID.randomUUID().toString());
}
this.iterator = this.map.entrySet().iterator();
}
private final ExecutorService executor = Executors.newCachedThreadPool();
private final class Accessor implements Runnable
{
private final Iterator<Map.Entry<String, String>> iterator;
public Accessor(Iterator<Map.Entry<String, String>> iterator)
{
this.iterator = iterator;
}
@Override
public void run()
{
while(iterator.hasNext()) {
Map.Entry<String, String> entry = iterator.next();
try
{
String st = Thread.currentThread().getName() + " - [" + entry.getKey() + ", " + entry.getValue() + ']';
} catch (Exception e)
{
e.printStackTrace();
}
}
}
}
private final class Mutator implements Runnable
{
private final Map<String, String> map;
private final Random random = new Random();
public Mutator(Map<String, String> map)
{
this.map = map;
}
@Override
public void run()
{
for (int i = 0; i < 100; i++)
{
this.map.remove("key" + random.nextInt(MAP_SIZE));
this.map.put("key" + random.nextInt(MAP_SIZE), UUID.randomUUID().toString());
}
}
}
private void run()
{
Accessor a1 = new Accessor(this.iterator);
Accessor a2 = new Accessor(this.iterator);
Mutator m = new Mutator(this.map);
executor.execute(a1);
executor.execute(m);
executor.execute(a2);
}
读线程和修改线程共享一个Iterator import java.util.Iterator; import java.util.Map; import java.util.Random; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ConcurrentMapIteration { private final Map<String, String> map = new ConcurrentHashMap<String, String>(); private final Iterator<Map.Entry<String, String>> iterator; private final static int MAP_SIZE = 100000; public static void main(String[] args) { new ConcurrentMapIteration().run(); } public ConcurrentMapIteration() { for (int i = 0; i < MAP_SIZE; i++) { map.put("key" + i, UUID.randomUUID().toString()); } this.iterator = this.map.entrySet().iterator(); } private final ExecutorService executor = Executors.newCachedThreadPool(); private final class Accessor implements Runnable { private final Iterator<Map.Entry<String, String>> iterator; public Accessor(Iterator<Map.Entry<String, String>> iterator) { this.iterator = iterator; } @Override public void run() { while (iterator.hasNext()) { Map.Entry<String, String> entry = iterator.next(); try { String st = Thread.currentThread().getName() + " - [" + entry.getKey() + ", " + entry.getValue() + ']'; } catch (Exception e) { e.printStackTrace(); } } } } private final class Mutator implements Runnable { private final Random random = new Random(); private final Iterator<Map.Entry<String, String>> iterator; private final Map<String, String> map; public Mutator(Map<String, String> map, Iterator<Map.Entry<String, String>> iterator) { this.map = map; this.iterator = iterator; } @Override public void run() { while (iterator.hasNext()) { try { iterator.remove(); this.map.put("key" + random.nextInt(MAP_SIZE), UUID.randomUUID().toString()); } catch (Exception ex) { ex.printStackTrace(); } } } } private void run() { Accessor a1 = new Accessor(this.iterator); Accessor a2 = new Accessor(this.iterator); Mutator m = new Mutator(map, this.iterator); executor.execute(a1); executor.execute(m); executor.execute(a2); }
结果:抛出java.lang.IllegalStateException异常。