Java并发性改进列表的线程安全性
我在实践中阅读了Java并发。它说这个类是线程安全的:Java并发性改进列表的线程安全性,java,concurrency,Java,Concurrency,我在实践中阅读了Java并发。它说这个类是线程安全的: package net.jcip.examples; import java.util.*; import net.jcip.annotations.*; /** * ImprovedList * * Implementing put-if-absent using composition * * @author Brian Goetz and Tim Peierls */ @ThreadSafe public class
package net.jcip.examples;
import java.util.*;
import net.jcip.annotations.*;
/**
* ImprovedList
*
* Implementing put-if-absent using composition
*
* @author Brian Goetz and Tim Peierls
*/
@ThreadSafe
public class ImprovedList<T> implements List<T> {
private final List<T> list;
public ImprovedList(List<T> list) { this.list = list; }
public synchronized boolean putIfAbsent(T x) {
boolean contains = list.contains(x);
if (contains)
list.add(x);
return !contains;
}
// Plain vanilla delegation for List methods.
// Mutative methods must be synchronized to ensure atomicity of putIfAbsent.
public int size() {
return list.size();
}
public boolean isEmpty() {
return list.isEmpty();
}
public boolean contains(Object o) {
return list.contains(o);
}
public Iterator<T> iterator() {
return list.iterator();
}
public Object[] toArray() {
return list.toArray();
}
public <T> T[] toArray(T[] a) {
return list.toArray(a);
}
public synchronized boolean add(T e) {
return list.add(e);
}
public synchronized boolean remove(Object o) {
return list.remove(o);
}
public boolean containsAll(Collection<?> c) {
return list.containsAll(c);
}
public synchronized boolean addAll(Collection<? extends T> c) {
return list.addAll(c);
}
public synchronized boolean addAll(int index, Collection<? extends T> c) {
return list.addAll(index, c);
}
public synchronized boolean removeAll(Collection<?> c) {
return list.removeAll(c);
}
public synchronized boolean retainAll(Collection<?> c) {
return list.retainAll(c);
}
public boolean equals(Object o) {
return list.equals(o);
}
public int hashCode() {
return list.hashCode();
}
public T get(int index) {
return list.get(index);
}
public T set(int index, T element) {
return list.set(index, element);
}
public void add(int index, T element) {
list.add(index, element);
}
public T remove(int index) {
return list.remove(index);
}
public int indexOf(Object o) {
return list.indexOf(o);
}
public int lastIndexOf(Object o) {
return list.lastIndexOf(o);
}
public ListIterator<T> listIterator() {
return list.listIterator();
}
public ListIterator<T> listIterator(int index) {
return list.listIterator(index);
}
public List<T> subList(int fromIndex, int toIndex) {
return list.subList(fromIndex, toIndex);
}
public synchronized void clear() { list.clear(); }
}
我不这么认为。构造函数参数列表可以在另一个线程中引用。因此,如果这个列表不是线程安全的,那么它在并发性方面可能不一致。如果此列表是线程安全的,则另一个线程使用列表锁对其进行操作,而使用ImprovedList的线程使用ImprovedList对象锁对其进行操作,因此它们仍然可以同时对其进行变异
谁能告诉我哪里错了?你是对的。如果您想使这样的列表真正线程安全,那么传入列表只是直接使用而不是复制的事实(例如)允许在任何其他对象的上下文中进行更改,该对象包含对该初始传入列表的引用 除此之外;这种实现甚至允许对不同步的列表进行硬修改;像
public T remove(int index) {
所以-我同意你的评估;这看起来并不完全是线程安全的。在某种程度上是这样;但是,作为90%的线程安全性,这就相当于一个90%完成的项目,对吗 你说得对。如果您想使这样的列表真正线程安全,那么传入列表只是直接使用而不是复制的事实(例如)允许在任何其他对象的上下文中进行更改,该对象包含对该初始传入列表的引用 除此之外;这种实现甚至允许对不同步的列表进行硬修改;像
public T remove(int index) {
所以-我同意你的评估;这看起来并不完全是线程安全的。在某种程度上是这样;但是,作为90%的线程安全性,这就相当于一个90%完成的项目,对吗 这本书的引文: 这是保证提供线程安全,只要我们的类 保存对基础列表的唯一未完成引用
因此,如果有人持有对同一列表的引用,那么该类就不能称为线程安全的,这是对的。但是你没有认真阅读这本书是错误的。这本书的引文: 这是保证提供线程安全,只要我们的类 保存对基础列表的唯一未完成引用
因此,如果有人持有对同一列表的引用,那么该类就不能称为线程安全的,这是对的。但是你没有认真阅读这本书是错误的。你错过了一个要点: ImprovedList假设一旦列表被传递给其构造函数,客户端将不再直接使用基础列表,而只通过ImprovedList访问它 因此,您的加薪不适用于此用例。ImprovedList与Collections.synchronizedListList类似,它只是一个包装类,可以防止使用内在锁对基础列表进行任何并发修改。如果提供给构造函数的列表不是直接访问的,而是通过ImprovedList访问的,它是线程安全的,这是您在本例中应该理解的
但实际上,一般来说,如果您共享提供给构造函数的非线程安全列表,并且在知道创建非线程安全列表的安全副本不是线程安全操作之后,您没有首先创建它的安全副本,那么它就不再是线程安全的了。但是请注意,共享非线程安全列表是一个错误,因此它不是一个真正的实际使用案例。您忽略了一个要点: ImprovedList假设一旦列表被传递给其构造函数,客户端将不再直接使用基础列表,而只通过ImprovedList访问它 因此,您的加薪不适用于此用例。ImprovedList与Collections.synchronizedListList类似,它只是一个包装类,可以防止使用内在锁对基础列表进行任何并发修改。如果提供给构造函数的列表不是直接访问的,而是通过ImprovedList访问的,它是线程安全的,这是您在本例中应该理解的
但实际上,一般来说,如果您共享提供给构造函数的非线程安全列表,并且在知道创建非线程安全列表的安全副本不是线程安全操作之后,您没有首先创建它的安全副本,那么它就不再是线程安全的了。但是,请注意,共享非线程安全列表是一个错误,因此它并不是一个真实的用例。谢谢,@GhostCat。我不知道为什么没有人告诉作者纠正它或只是澄清前提条件。太令人困惑了。试着给他们发邮件/推特。。。或许,我们都错了;忽视一些事情;所以你可以要求那些人澄清-好啊我将邀请作者回答这个问题并指出我可能的错误。为了为这本书的作者辩护,可能是Java世界最著名的并发专家:1书中的引文:这保证提供线程安全性这么长时间
因为我们的类持有对基础列表的唯一突出引用;2非同步删除方法不是书中的,是@Richard添加的。对。考虑到他们是真正的专家,我也想到了我错过的东西。代码来自他们的网站谢谢,@GhostCat。我不知道为什么没有人告诉作者纠正它或只是澄清前提条件。太令人困惑了。试着给他们发邮件/推特。。。或许,我们都错了;忽视一些事情;所以你可以要求那些人澄清-好啊我将邀请作者回答这个问题,并指出我可能的错误。为这本书的作者辩护,这本书可能是Java世界最著名的并发专家:1书中的引文:只要我们的类持有对底层列表的唯一杰出引用,这保证提供线程安全;2非同步删除方法不是书中的,是@Richard添加的。对。考虑到他们是真正的专家,我也想到了我错过的东西。代码来自他们的网站我想你在列表之前遗漏了一点文字:像Collections.synchronizedList和其他Collections包装器一样,ImprovedList假设一旦一个列表被传递给它的构造函数,客户端就不会再直接使用底层列表,仅通过ImprovedList访问它。我认为您缺少列表之前的一段文字:与Collections.synchronizedList和其他集合包装器一样,ImprovedList假设一旦将列表传递给其构造函数,客户端将不再直接使用基础列表,仅通过ImprovedList访问它。这本书提到了ImprovedList,额外的同步层的性能损失很小,因为对底层的访问总是没有争议的。参见包含改进列表列表的同一页底部的脚注7,内容为:[7]由于基础列表上的同步保证是无争用的,因此速度很快,因此惩罚很小;见第11章。我的问题是,如果多个线程同时访问ImprovedList怎么办?那怎么可能是无可辩驳的呢?我误解了什么?谢谢。书中提到了ImprovedList,因为对底层的访问总是毫无争议的,所以额外的同步层的性能损失很小。参见包含改进列表列表的同一页底部的脚注7,内容为:[7]由于基础列表上的同步保证是无争用的,因此速度很快,因此惩罚很小;见第11章。我的问题是,如果多个线程同时访问ImprovedList怎么办?那怎么可能是无可辩驳的呢?我误解了什么?谢谢