我正在寻找关于如何使用Java中的锁使这个代码成为线程安全的建议。我知道有很多带锁的陷阱;可能出现的模糊问题,竞争条件等。以下是我想要实现的基本思路,实施起来相当天真:
public class MultipleThreadWriter {
boolean isUpgrading=false;
boolean isWriting=false;
public void writeData(String uniqueId) {
if (isUpgrading)
//block until isUpgrading is false
isWriting = true;
{
//do write stuff
}
isWriting = false;
}
public void upgradeSystem() {
if (isWriting)
//block until isWriting is false
isUpgrading = true;
{
//do updates
}
isUpgrading = false;
}
}
基本思想是允许多个线程同时写入数据。没关系,因为没有两个线程会写入属于同一uniqueId的数据。但是,“系统升级”操纵所有uniqueIds的数据,因此它必须阻塞(排队等待)直到没有数据被写入才能启动,此时它会阻止所有写入,直到完成为止。 (绝对不是消费者/生产者模式在这里进行 - 升级是随意进行的,即与正在写入的数据无关。)
答案 0 :(得分:2)
这听起来像readers-writer lock的好应用。
然而,在这种情况下,您的读者"是可以同时运行的小型更新任务,以及您的" writer"是系统升级任务。
Java标准库中有一个实现:
java.util.concurrent.locks.ReentrantReadWriteLock
锁具有合理和非公平模式。如果您希望系统升级在计划后尽快运行,请使用锁的 fair 模式。如果您希望在空闲时间应用升级(即等到没有小的更新),那么您可以使用非公平模式。
由于这是读者 - 作者锁定的一种非正统应用(你的读者实际上也在写作!),请务必在代码中对此进行评论。您甚至可以考虑围绕提供ReentrantReadWriteLock
vs localUpdateLock
方法的globalUpdateLock
类编写包装器,这些方法分别委托给readLock
和writeLock
。
答案 1 :(得分:0)
根据@DaoWen的回答,这是我未经测试的解决方案。
public class MultipleThreadWriter {
private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
private final Lock r = rwl.readLock();
private final Lock w = rwl.writeLock();
public void writeData() {
r.lock();
try {
//do write stuff
} finally {
r.unlock();
}
}
public void upgradeSystem() {
w.lock();
try {
//do updates
} finally {
w.unlock();
}
}
}