ConcurrentHashMap

在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异常。

posted @ 2020-06-11 15:32  w'c's  阅读(173)  评论(0编辑  收藏  举报