线程安全集合
默认情况下,各种 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,并且可能与其他操作同时进行。
自迭代器创建以来队列中包含的元素将只返回一次。
并发集合是一个 允许多个线程同时访问的[集合]。
不同的线程通常可以遍历集合的内容并添加或者删除元素。
集合负责确保集合不会损坏。
