线程安全集合

默认情况下,各种 Collection 类型不是线程安全的。

然而,使集合线程安全是相当容易的。

List threadSafeList = Collections.synchronizedList(new ArrayList());
Set threadSafeSet = Collections.synchronizedSet(new HashSet());
Map threadSafeMap = Collections.synchronizedMap(new HashMap());

当你创建一个线程安全的集合时,你不应该通过原始集合访问它,只能通过线程安全包装器访问它。

从 Java 5 开始,java.util.collections 有几个新的线程安全集合,不需要各种 Collections.synchronized 方法。

List threadSafeList = new CopyOnWriteArrayList();
Set threadSafeSet = new ConcurrentHashSet();
Map threadSafeMap = new ConcurrentHashMap();

插入 ConcurrentHashMap

public class InsertIntoConcurrentHashMap
{
      public static void main(String[] args)
      {
           ConcurrentHashMap concurrentHashMap = new ConcurrentHashMap<>();
           SomeObject value = new SomeObject();
           Integer key = 1;
           SomeObject previousValue = concurrentHashMap.putIfAbsent(1, value);
           if (previousValue != null)
           {
                //Then some other value was mapped to key = 1. 'value' that was passed to
                //putIfAbsent method is NOT inserted, hence, any other thread which calls
                //concurrentHashMap.get(1) would NOT receive a reference to the 'value'
                //that your thread attempted to insert. Decide how you wish to handle
                //this situation.
          }
          else
          {
         //'value' reference is mapped to key = 1.
      }
   }
}

并发集合

并发集合是线程安全集合的泛化,允许在并发环境中更广泛地使用。

虽然线程安全集合具有从多个线程中安全添加或者删除元素的功能,但它们不一定在同一上下文中具有安全迭代(一个线程可能无法安全地迭代一个线程中的集合,而另一个线程通过添加/删除元素)。

这是使用并发集合的地方。

由于迭代通常是集合中几种批量方法的基本实现,例如 addAll、removeAll 或者集合复制(通过构造函数或者其他方式)、排序……并发集合的用例实际上非常大。

例如,Java SE 5 java.util.concurrent.CopyOnWriteArrayList 是一个线程安全的并发 List 实现,它的 javadoc 声明:

“快照”样式的迭代器方法使用对创建迭代器时数组状态的引用。
这个数组在迭代器的生命周期内永远不会改变,所以干扰是不可能的,并且迭代器保证不会抛出 ConcurrentModificationException 。

因此,以下代码是安全的:

public class ThreadSafeAndConcurrent {
public static final List LIST = new CopyOnWriteArrayList<>();
public static void main(String[] args) throws  InterruptedException {
      Thread modifier = new Thread(new ModifierRunnable());
      Thread iterator = new Thread(new IteratorRunnable());
      modifier.start();
      iterator.start();
      modifier.join();
      iterator.join();
}
public static final class ModifierRunnable implements Runnable {
      @Override
      public void run() {
          try {
              for (int i = 0; i < 50000; i++) {
                   LIST.add(i);
              }
          } catch (Exception e) {
                   e.printStackTrace();
          }
     }
}
public static final class IteratorRunnable implements Runnable {
     @Override
     public void run() {
          try {
               for (int i = 0; i < 10000; i++) {
                    long total = 0;
                    for(Integer inList : LIST) {
                         total += inList;
                    }
                    System.out.println(total);
               }
       } catch (Exception e) {
               e.printStackTrace();
       }
   }
}
}

另一个关于迭代的并发集合是 ConcurrentLinkedQueue:

迭代器是弱一致的,返回元素反映了在迭代器创建时或者之后的某个时刻的队列状态。
它们不会抛出 java.util.ConcurrentModificationException,并且可能与其他操作同时进行。
自迭代器创建以来队列中包含的元素将只返回一次。

Java 中的并发集合

并发集合是一个 允许多个线程同时访问的[集合]。
不同的线程通常可以遍历集合的内容并添加或者删除元素。
集合负责确保集合不会损坏。

日期:2020-06-02 22:15:16 来源:oir作者:oir