列表同步问题

java中集合框架中的类多数都是不同步的,如ArrayList,LinkedList,如果需要在多线程中同步需要使用Collections.synchronizedList,使用中经常出现ConcurrentModificationException 的异常情况,举例说明

public class EventObserver {

private static class EventObseverHolder {
private static final EventObserver sInstance = new EventObserver();
}

private List<EventListener> mList = Collections.synchronizedList(new ArrayList<EventListener>());

public static EventObserver getInstance() {
return EventObseverHolder.sInstance;
}

public void addEventListener(EventListener listener) {
if (null == listener) {
return;
}
synchronized (mList) {
if (mList.contains(listener)) {
return;
}
mList.add(listener);
}
}

public void removeEventListener(EventListener listener) {
if (null == listener) {
return;
}
mList.remove(listener);
}

public void sendEvent() {
synchronized (mList) {
Iterator<EventListener> iterator = mList.iterator();
while (iterator.hasNext()) {
EventListener listener = iterator.next();
listener.onEvent();
}
}
}

interface EventListener {
void onEvent();
}
}

上面代码本已实现列表同步,但是当出现onEvent中调用removeEventListener情况就会导致ConcurrentModificationException 异常,当然多数人应该不会直接出现这种情况,这种一般出现在间接调用中,比较难发现,如果出现这样问题,可以梳理一下调用流程。


ConcurrentModificationException 这个异常是怎么出现的,下面给出ArrayList源码出处

public Iterator<E> iterator() {
return new Itr();
    }

下面是迭代器初始化一些东西

private class Itr implements Iterator<E> {
/**
* Index of element to be returned by subsequent call to next.
*/
int cursor = 0;


/**
* Index of element returned by most recent call to next or
* previous.  Reset to -1 if this element is deleted by a call
* to remove.
*/
int lastRet = -1;


关键这个初始化,
int expectedModCount = modCount;


public E next() {

    遍历时候检查如下
            checkForComodification();

    .....

}

final void checkForComodification() {
   if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}


当在列表遍历的时候,移除其中一项(非迭代器移除如removeEventListener中的移除),将导致modCount 这个值发生变化,expectedModCount不会被修改,导致这两个值不会相等


EventObserver 这个能否在多线程同步呢?答案是肯定的,EventObserver 中同步代码块锁的对象跟列表原子操作是一样的,请看源码:

public static <T> List<T> synchronizedList(List<T> list) {
return (list instanceof RandomAccess ?
                new SynchronizedRandomAccessList<T>(list) :
                new SynchronizedList<T>(list));
    }

ArrayList继承了RandomAccess接口,所以这里返回SynchronizedRandomAccessList对象,接下来看SynchronizedRandomAccessList

static class SynchronizedRandomAccessList<E>
extends SynchronizedList<E>
implements RandomAccess {

        SynchronizedRandomAccessList(List<E> list) {
            super(list);
        }

SynchronizedRandomAccessList(List<E> list, Object mutex) {
            super(list, mutex);
        }

SynchronizedRandomAccessList又继承了SynchronizedList,看父类SynchronizedList

static class SynchronizedList<E>
extends SynchronizedCollection<E>
implements List<E> {
        static final long serialVersionUID = -7754090372962971524L;

final List<E> list;

SynchronizedList(List<E> list) {
   super(list);
   this.list = list;
}
SynchronizedList(List<E> list, Object mutex) {
            super(list, mutex);
   this.list = list;
        }

.....

}

SynchronizedList父类SynchronizedCollection,其中的锁是mutex对象

static class SynchronizedCollection<E> implements Collection<E>, Serializable {
// use serialVersionUID from JDK 1.2.2 for interoperability
private static final long serialVersionUID = 3053995032091335093L;


final Collection<E> c;  // Backing Collection
final Object mutex;     // Object on which to synchronize


SynchronizedCollection(Collection<E> c) {
            if (c==null)
                throw new NullPointerException();
   this.c = c;
            mutex = this;
        }
SynchronizedCollection(Collection<E> c, Object mutex) {
   this.c = c;
            this.mutex = mutex;
        }

....

public int size() {
   synchronized(mutex) {return c.size();}
        }

....

}

mutex = this;表明同步列表原子操作锁对象与EventObserver 中同步代码块锁的对象是相同的。



很少去写一些东西,难免有错误,还请大家指正,谢谢!



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值