多线程Java并发:并发添加和清除列表项
考虑以下方法:
public void add(final List<ReportingSTG> message) {
if(stopRequested.get()) {
synchronized (this) {
if(stopRequested.get()) {
retryQueue.put(message);
}
}
}
messages.add(message);
if(messages.size() >= batchSize && waitingThreads.get() == 0) {
synchronized (this) {
if(messages.size() >= batchSize && waitingThreads.get() == 0) {
final List<List<ReportingSTG>> clone = new ArrayList<List<ReportingSTG>>(messages);
messages.clear();
if(processors.size()>=numOfProcessors) {
waitingThreads.incrementAndGet();
waitForProcessor();
waitingThreads.decrementAndGet();
}
startProcessor(clone);
}
}
}
}
特别是这两条线:
1: final List<List<ReportingSTG>> clone = new ArrayList<List<ReportingSTG>>(messages);
2: messages.clear();
如果线程A进入同步块并获得当前对象的锁,这是否意味着该对象的实例属性状态不能被同步块之外的其他线程更改(而线程A处于同步块中)
例如,线程执行的行1->;线程B输入了方法并添加了新的列表条目(messages.add(message))->;线程执行的第2行->;线程B添加的条目被删除(与其他条目一起)。这种情况可能吗?或者线程B将等待线程A释放锁,然后才会删除列表项
消息是一个非静态同步列表
UPD:更新方法,可能的解决方案:
public void add(final List<ReportingSTG> message) {
if(stopRequested.get()) {
synchronized (this) {
if(stopRequested.get()) {
retryQueue.put(message);
}
}
}
while (addLock.get()){
try {
Thread.sleep(1);
} catch (InterruptedException e) {}
}
messages.add(message);
if(messages.size() >= batchSize && waitingThreads.get() == 0) {
synchronized (this) {
if(messages.size() >= batchSize && waitingThreads.get() == 0) {
addLock.set(true);
final List<List<ReportingSTG>> clone = new ArrayList<List<ReportingSTG>>(messages);
messages.clear();
addLock.set(false);
if(processors.size()>=numOfProcessors) {
waitingThreads.incrementAndGet();
waitForProcessor();
waitingThreads.decrementAndGet();
}
startProcessor(clone);
}
}
}
}
addLock-AtomicBoolean,默认为false
# 1 楼答案
我最近组织了一个
DoubleBufferedList
班。也许使用它可以完全避免你的问题。顾名思义,它实现了双缓冲算法,但用于列表这个类允许你有许多生产者线程和消费者线程。每个生产者线程都可以添加到当前列表中。每个使用者线程都会获取整个当前列表以进行处理
它也不使用锁,只使用原子,所以应该可以高效运行
请注意,其中大部分是测试代码。您可以在
// TESTING
注释之后删除所有内容,但您可能会发现测试的严格性令人欣慰