gpt4 book ai didi

java - 具有原子替换的线程安全可序列化集合

转载 作者:塔克拉玛干 更新时间:2023-11-02 19:57:31 27 4
gpt4 key购买 nike

当多个线程通过 RMI 访问同一服务器时,我的程序遇到了问题。服务器包含一个列表作为缓存,并执行一些昂贵的计算,有时会更改该列表。计算完成后,列表将被序列化并发送给客户端。

第一个问题:如果列表在序列化时发生变化(例如,由不同的客户端请求某些数据),(可能)抛出 ConcurrentModificationException,导致 EOFException 用于客户端的 RMI 调用/反序列化。

因此我需要某种列表结构,它对于序列化是“稳定的”,同时可能被不同的线程更改。

我们尝试过的解决方案:

  • 常规 ArrayList/Set - 由于并发而无法正常工作
  • 在每次序列化之前深度复制整个结构 - 太昂贵了
  • CopyOnWriteArrayList - 也很昂贵,因为它复制了列表

揭示第二个问题:我们需要能够自动替换列表中当前非线程安全的任何元素(先删除,然后添加(这甚至更昂贵))或只能通过锁定列表来实现,因此只能按顺序执行不同的线程。

因此我的问题是:

Do you know of a Collection implementation which allows us to serialize the Collection thread-safe while other Threads modify it and which contains some way of atomically replacing elements?

A bonus would be if the list would not need to be copied before serialization! Creating a snapshot for every serialization would be okay, but still meh :/

问题说明(C=计算,A=添加到列表,R=从列表中删除,S=序列化)

Thread1 Thread2
C
A
A C
C A
S C
S R <---- Remove and add have to be performed without Thread1 serializing
S A <---- anything in between (atomically) - and it has to be done without
S S blocking other threads computations and serializations for long
S and not third thread must be allowed to start serializing in this
S in-between state
S

最佳答案

最简单的解决方案是对 ArrayList 进行外部同步,可能通过这样的读写锁:

public class SyncList<T> implements Serializable {
private static final long serialVersionUID = -6184959782243333803L;

private List<T> list = new ArrayList<>();
private transient Lock readLock, writeLock;

public SyncList() {
ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
readLock = readWriteLock.readLock();
writeLock = readWriteLock.writeLock();
}

public void add(T element) {
writeLock.lock();
try {
list.add(element);
} finally {
writeLock.unlock();
}
}

public T get(int index) {
readLock.lock();
try {
return list.get(index);
} finally {
readLock.unlock();
}
}

public String dump() {
readLock.lock();
try {
return list.toString();
} finally {
readLock.unlock();
}
}

public boolean replace(T old, T newElement) {
writeLock.lock();
try {
int pos = list.indexOf(old);
if (pos < 0)
return false;
list.set(pos, newElement);
return true;
} finally {
writeLock.unlock();
}
}

private void writeObject(ObjectOutputStream out) throws IOException {
readLock.lock();
try {
out.writeObject(list);
} finally {
readLock.unlock();
}
}

@SuppressWarnings("unchecked")
private void readObject(ObjectInputStream in) throws IOException,
ClassNotFoundException {
list = (List<T>) in.readObject();
ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
readLock = readWriteLock.readLock();
writeLock = readWriteLock.writeLock();
}
}

提供您喜欢的任何操作,只需正确使用读锁或写锁即可。

关于java - 具有原子替换的线程安全可序列化集合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32826031/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com