Java与同步链表
我必须回答你的问题。第一个问题是为什么我们运行这个函数时会出现ConcurrentModificationExceptionJava与同步链表,java,multithreading,collections,synchronization,Java,Multithreading,Collections,Synchronization,我必须回答你的问题。第一个问题是为什么我们运行这个函数时会出现ConcurrentModificationException public static void testList() { List<String> list = new ArrayList<String>(); list.add("str3"); for (String st : list) { if (st.equalsIgnoreCase("str3")) {
public static void testList() {
List<String> list = new ArrayList<String>();
list.add("str3");
for (String st : list) {
if (st.equalsIgnoreCase("str3")) {
list.remove("str3");
}
}
System.out.println(list);
}
publicstaticvoidtestlist(){
列表=新的ArrayList();
列表。添加(“str3”);
for(字符串st:list){
if(st.equalsIgnoreCase(“str3”)){
列表。删除(“str3”);
}
}
系统输出打印项次(列表);
}
我喜欢这个东西,因为增强了使用迭代器(它检查modificationscont
),但我要求确定。这就是例外的原因
第二个问题是我是否使用了Collections.synchronizedList(newlinkedlist())代码>
我可以使用2个或更多的增强for循环吗?例如,我必须执行线程,有时第一个线程从集合中删除元素,有时第二个线程在集合中添加元素。我认为即使在我们使用迭代器时也应该进行线程保存(我认为迭代器的功能得到了增强)。
提前谢谢。第一个问题,是的。如果列表正在枚举,则修改列表时,这是常见的异常
关于第二个问题,是的。但是您需要为each for循环使用synchronized
块如果您在迭代列表时从列表中删除元素,您将得到一个ConcurrentModificationException
。为了避免这种情况,您应该使用显式迭代器而不是增强的for
循环,并在找到必须删除的元素时,在迭代器上而不是在列表上调用remove()
:
for (Iterator<String> i = list.iterator(); i.hasNext(); ) {
String st = i.next();
if (st.equalsIgnoreCase("str3")) {
// Remove the element that the iterator is currently pointing to
i.remove();
}
}
for(迭代器i=list.Iterator();i.hasNext();){
字符串st=i.next();
if(st.equalsIgnoreCase(“str3”)){
//删除迭代器当前指向的元素
i、 删除();
}
}
仅使用集合包装列表。synchronizedList(…)
不能使多个线程同时在列表上迭代,其中一个线程正在从列表中删除元素。执行此操作时,您仍然会得到一个ConcurrentModificationException
。使用集合包装列表。synchronizedList(…)将使列表上的各个方法同步,但在多个方法上没有同步
您必须确保,如果一个线程正在从列表中删除元素,则通过正确同步您自己的迭代和删除元素的方法,没有其他线程在列表中迭代。迭代器在SynchronizedCollection中不同步。我已附上同步收集代码
static class SynchronizedCollection<E> implements Collection<E>, Serializable {
private static final long serialVersionUID = 3053995032091335093L;
final Collection<E> c; // Backing Collection
final Object mutex; // Object on which to synchronize
SynchronizedCollection(Collection<E> c) {
this.c = Objects.requireNonNull(c);
mutex = this;
}
SynchronizedCollection(Collection<E> c, Object mutex) {
this.c = Objects.requireNonNull(c);
this.mutex = Objects.requireNonNull(mutex);
}
public int size() {
synchronized (mutex) {return c.size();}
}
public boolean isEmpty() {
synchronized (mutex) {return c.isEmpty();}
}
public boolean contains(Object o) {
synchronized (mutex) {return c.contains(o);}
}
public Object[] toArray() {
synchronized (mutex) {return c.toArray();}
}
public <T> T[] toArray(T[] a) {
synchronized (mutex) {return c.toArray(a);}
}
public Iterator<E> iterator() {
return c.iterator(); // Must be manually synched by user!
}
public boolean add(E e) {
synchronized (mutex) {return c.add(e);}
}
public boolean remove(Object o) {
synchronized (mutex) {return c.remove(o);}
}
public boolean containsAll(Collection<?> coll) {
synchronized (mutex) {return c.containsAll(coll);}
}
public boolean addAll(Collection<? extends E> coll) {
synchronized (mutex) {return c.addAll(coll);}
}
public boolean removeAll(Collection<?> coll) {
synchronized (mutex) {return c.removeAll(coll);}
}
public boolean retainAll(Collection<?> coll) {
synchronized (mutex) {return c.retainAll(coll);}
}
public void clear() {
synchronized (mutex) {c.clear();}
}
public String toString() {
synchronized (mutex) {return c.toString();}
}
// Override default methods in Collection
@Override
public void forEach(Consumer<? super E> consumer) {
synchronized (mutex) {c.forEach(consumer);}
}
@Override
public boolean removeIf(Predicate<? super E> filter) {
synchronized (mutex) {return c.removeIf(filter);}
}
@Override
public Spliterator<E> spliterator() {
return c.spliterator(); // Must be manually synched by user!
}
@Override
public Stream<E> stream() {
return c.stream(); // Must be manually synched by user!
}
@Override
public Stream<E> parallelStream() {
return c.parallelStream(); // Must be manually synched by user!
}
private void writeObject(ObjectOutputStream s) throws IOException {
synchronized (mutex) {s.defaultWriteObject();}
}
}
静态类SynchronizedCollection实现可序列化的集合{
私有静态最终长serialVersionUID=3053995032091335093L;
最终集合c;//支持集合
最终对象互斥体;//要同步的对象
SynchronizedCollection(集合c){
this.c=Objects.requirennull(c);
互斥=这个;
}
SynchronizedCollection(集合c,对象互斥){
this.c=Objects.requirennull(c);
this.mutex=Objects.requirennull(互斥);
}
公共整数大小(){
已同步(互斥){返回c.size();}
}
公共布尔值为空(){
已同步(互斥){return c.isEmpty();}
}
公共布尔包含(对象o){
已同步(互斥){返回c.contains(o);}
}
公共对象[]toArray(){
已同步(互斥){返回c.toArray();}
}
公共T[]toArray(T[]a){
已同步(互斥){返回c.toArray(a);}
}
公共迭代器迭代器(){
返回c.iterator();//必须由用户手动同步!
}
公共布尔加法(E){
已同步(互斥){返回c.add(e);}
}
公共布尔删除(对象o){
已同步(互斥){返回c.remove(o);}
}
公共布尔containsAll(集合coll){
已同步(互斥){返回c.containsAll(coll);}
}
公共布尔addAll(集合coll){
已同步(互斥){返回c.removeAll(coll);}
}
公共布尔值保留(集合集合集合){
已同步(互斥){返回c.retainAll(coll);}
}
公共空间清除(){
已同步(互斥){c.clear();}
}
公共字符串toString(){
已同步(互斥){返回c.toString();}
}
//覆盖集合中的默认方法
@凌驾
public void forEach(ConsumerTanks,您的答案。因此,如果我有两个线程,并且每个线程中都有一个迭代器(并且其中至少一个线程更改了集合),我必须同步迭代(因为如果一个线程做了更改,另一个迭代器将检查modCount和Boom)?还有一个问题-如何实现Enhanced for,它会引发异常,但普通迭代器不会。提前感谢。是的,如果至少有一个线程正在更改集合,则需要在整个循环中同步。第二个问题:技巧是通过调用remove()来删除
在迭代器上,而不是在列表本身上-这样迭代器知道集合已更改。通过增强的for
-循环,您无法访问迭代器,因此无法在迭代器上调用remove()
。感谢您的回答。这与Collections.synchronizedList的内容大致相同(...)
可以,也不会在方法调用之间保护您免受ConcurrentModificationException
的影响。@Jesper这不多也不少。这是synchronizedList code Only为您解答!Jesper对您有帮助吗?如果我在某个地方迭代集合,使用同步集合的原因是什么?我的意思是我必须nchronized了这个迭代b