pjj*_*pjj 5 java collections parallel-processing multithreading thread-safety
从这个来源可以阅读:
值得一提的是,同步和并发集合只会使集合本身线程安全,而不是内容。
我认为如果Collection是线程安全的,那么它的内容将隐式是线程安全的。
我的意思是,如果两个线程无法访问我的Collection对象,那么我的Collection对象所持有的对象将隐式成为线程安全的。
我错过了这一点,有人可以用一个例子来解释我吗?
存储在线程安全集合中的对象可以泄漏到外部并以非线程安全的方式使用。
详细解答:
我认为如果 Collection 是线程安全的,那么它的内容将隐式是线程安全的,我的意思是如果两个线程无法访问我的 Collection 对象,那么我的 Collection 对象所持有的对象将隐式成为线程安全的。
我知道我确实没有抓住重点,有人可以用一个例子来解释我。
考虑以下代码,该代码使用两个线程将中的元素添加到同一个非线程安全列表中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)
Run Code Online (Sandbox Code Playgroud)
所有这些都是方法调用期间竞争条件的结果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));
}
Run Code Online (Sandbox Code Playgroud)
让我们List通过调用Collections.synchronizedList使用线程安全来修复竞争条件。因此,让我们将之前的代码修改为:
List<Integer> list = Collections.synchronizedList(new ArrayList<>());
Run Code Online (Sandbox Code Playgroud)
您可以根据需要多次运行它;最终结果总是相同的,即 90。我们已经知道了这么多。让我们展示一下:
值得一提的是,同步和并发集合只会使集合本身线程安全,而不是内容。
您只需要修改之前的代码:
List<Integer> list = Collections.synchronizedList(new ArrayList<>());
Run Code Online (Sandbox Code Playgroud)
到:
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);
...
Run Code Online (Sandbox Code Playgroud)
和瞧!您的情况与我们展示的第一个示例(即竞争条件)完全相同。即使列表LIST_THREAD_SAFE是线程安全的,它的内容也不是。因此,
同步和并发集合只会使集合本身成为线程安全的,而不是内容。
| 归档时间: |
|
| 查看次数: |
276 次 |
| 最近记录: |