1

http://docs.oracle.com/javase/7/docs/api/java/util/LinkedList.html

请注意,此实现不同步。如果多个线程同时访问一个链表,并且至少有一个线程在结构上修改了链表,则必须对外同步。

如果你不这样做会发生什么?您可以使 JVM 崩溃、导致异常或只是产生不一致的状态吗?

如果只有一位写入者,但并发读取不受保护怎么办?你仍然可以崩溃并弄乱状态,或者只是产生不一致的读取吗?

这是特定于实现的,还是规范保证一定程度的安全性和/或原子性?

4

4 回答 4

1

在多线程环境中使用不同步的集合会导致诸如脏读(不一致的数据状态)和ConcurrentModificationException(主要是当一个线程修改了集合的内容而另一个线程正在迭代它时)之类的问题。

根据您的用例,这可能会导致您的应用程序崩溃或死锁(当一个线程由于上述原因被 JVM 关闭时,未捕获的异常)。更糟糕的是,它可能会导致难以追踪的狡猾问题和错误结果。但是,它不会使 JVM 本身崩溃。

我建议看一下java.util.concurrent包装。你会发现各种各样的线程安全、高效的集合。它们中的大多数都有弱一致的迭代器,返回的元素反映了在迭代器创建时或之后的某个时间点的集合状态。这意味着它们不会抛出ConcurrentModificationException,并且可以与其他操作同时进行。

有关 Java 内存模型及其保证的信息,请参阅(非常值得一读!)。

于 2013-07-13T10:16:10.710 回答
0

您可能不会使应用程序崩溃,但您的不同线程将遭受DIRTY_READ问题。

于 2013-07-13T09:52:04.657 回答
0

线程安全的糟糕之处在于,错误很少发生并且难以重现。Java 在很大程度上将线程的处理委托给操作系统,因此当多个任务同时运行时,程序员无法准确控制线程如何以及何时被操作系统暂停和切换。观察到的各种错误的频率可能会有所不同,具体取决于 CPU 是单核还是双核或四核。

并发错误很少会“使系统崩溃”,更可能的问题是状态不一致。但是,如果您正在使用 Iterator 遍历集合,而另一个 Thread 修改该集合,那么您将获得ConcurrentModificationException。例如:

 Set<String> words; //a field that can be accessed by other threads.
 // may throw ConcurrentModificationException
 public ArrayList<String> unsafeIteration()  {
   ArrayList<String> longWords = new ArrayList<>();
   for(String word : words) {
      if(word.length()>4)
        longWords.add(word);
   }
   return longWords ;
 }

Iterator 的实现尝试检测它正在迭代的集合的并发修改,但这只是“快速失败”的最大努力尝试。通过抛出异常让程序失败比出现不可预测的行为要好得多。javadocs 做出此免责声明:

请注意,不能保证快速失败的行为,因为一般来说,在存在不同步的并发修改的情况下,不可能做出任何硬保证。快速失败操作会尽最大努力抛出 ConcurrentModificationException。因此,编写一个依赖此异常来确保其正确性的程序是错误的:ConcurrentModificationException 应该仅用于检测错误。

如果我们只是从一个集合中读取数据,get那么我们不会看到这个异常,但我们确实会冒着状态不一致的风险。有时这不是需要修复的问题。如果只有一个线程写入一个字段,并且所有线程总是看到该字段中的最新值并不重要,我认为只要你远离迭代器就可以了。

于 2013-07-13T10:24:47.807 回答
0

集合框架的根类 java.util.Collection 的 Javadoc 写道:

由每个集合决定自己的同步策略。在实现没有更强有力的保证的情况下,未定义的行为可能是由于对正在被另一个线程改变的集合上的任何方法的调用引起的;这包括直接调用,将​​集合传递给可能执行调用的方法,以及使用现有迭代器检查集合。

“未定义的行为”意味着集合可以为所欲为,集合框架的整个 javadoc 都是无效的。例如,一个元素可能在被删除后仍然存在于集合中,或者在添加后不存在。例如,如果线程 1 添加到 HashMap 并在线程 2 插入内容时触发调整大小,则来自线程 2 的插入可能会丢失。

但是,如果缺少同步会导致 JVM 本身崩溃,我会感到非常惊讶。

于 2013-07-13T10:44:41.600 回答