java - 同步和并发集合如何是线程安全的,但它们的内容不是

标签 java multithreading collections parallel-processing thread-safety

从这里 source可以阅读:

It's worth mentioning that synchronized and concurrent collections only make the collection itself thread-safe and not the contents.


我想如果Collection是线程安全的,那么它的内容将隐式是线程安全的。
我的意思是如果两个线程不能访问我的 Collection对象然后是我的对象 Collection持有的对象将隐式变为线程安全的。
我错过了这一点,有人可以用一个例子来解释我吗?

最佳答案

tl;博士
存储在线程安全集合中的对象可以泄漏到外部并以非线程安全的方式使用。
详细解答:

I thought if Collection is thread-safe then its content will implicitly be thread-safe, I mean if two threads cannot access my Collection object then the object which my Collection object is holding will implicitly become thread-safe.

I know sure I missing the point, could someone please explain me with an example.


考虑以下使用两个线程添加到同一 的代码。非线程安全列表 来自 0 to 10 的元素.最后,主线程对该列表的所有元素求和。最终结果应该与 0 + 0 + 1 + 1 + ... 9 + 9 = 90. 相同然而,如果你多次执行代码,你会得到不同的值,有时甚至是下面的 NPE :
Exception in thread "main" java.lang.NullPointerException
    at java.base/java.util.stream.ReduceOps$1ReducingSink.accept(ReduceOps.java:80)
    at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1655)
    at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
    at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913)
    at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.base/java.util.stream.ReferencePipeline.reduce(ReferencePipeline.java:553)
    at Z.CollectionThreadSafe.main(CollectionThreadSafe.java:26)
所有这些都是方法调用期间竞争条件的结果 add .
private static void addToList(List<Integer> list) {
    for (int i = 0; i < 10; i++)
        list.add(i);
}

public static void main(String[] arg) throws InterruptedException {
    final int TOTAL_THREADS = 2;
    List<Integer> list = new ArrayList<>();
    ExecutorService pool = Executors.newFixedThreadPool(TOTAL_THREADS);
    for (int i = 0; i < TOTAL_THREADS; i++) {
        pool.submit(() -> addToList(list));
    }
    pool.shutdown();
    pool.awaitTermination(10, TimeUnit.SECONDS);
    System.out.println(list.stream().reduce(0, Integer::sum));
}
让我们使用线程安全 List 修复竞争条件调用 Collections.synchronizedList .因此,让我们将之前的代码修改为:
List<Integer> list = Collections.synchronizedList(new ArrayList<>());
您可以根据需要多次运行它;最终结果总是相同的,即 90 .我们已经知道了这么多。让我们展示一下:

It's worth mentioning that synchronized and concurrent collections only make the collection itself thread-safe and not the contents.


您只需要修改之前的代码:
List<Integer> list = Collections.synchronizedList(new ArrayList<>());
到:
final List<List<Integer>> LIST_THREAD_SAFE = Collections.synchronizedList(new ArrayList<>());
LIST_THREAD_SAFE.add(new ArrayList<>());
List<Integer> list = LIST_THREAD_SAFE.get(0);
...
瞧!您的情况与我们展示的第一个示例完全相同(即竞争条件)。即使列表LIST_THREAD_SAFE是线程安全的,它的内容不是。因此,

synchronized and concurrent collections only make the collection itself thread-safe and not the contents.

关于java - 同步和并发集合如何是线程安全的,但它们的内容不是,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66059994/

相关文章:

java - 数据没有推送到浏览器?

java - hibernate 线程如何向自身发送中断?

Java 线程 : Given program isn't behaving properly

java - Collection 的 contains 方法是否会为添加到其中的实例返回 false?

java - 如何使用 application.properties 在 Spring 中禁用 csrf?

java - Tomcat 6 - connectTimeout 仍在默认执行

java - Gradle说Java Home在macOS Catalina中有所不同

c - 线程中的全局变量指针

ruby - ruby 集合/可枚举的炫酷技巧和富有表现力的片段

java - 在 Java 中转换 'ArrayList<String> to ' String[]'