【发布时间】:2012-10-30 16:56:21
【问题描述】:
对于 Java 中的 MCS 锁,我得到了一些非常奇怪的缓存行为。基本上,它最多可用于四个线程(我机器上的内核数),但会卡住更多线程。调试的时候发现程序卡在了线上
while (qnode.locked);
lock() 函数内部。调试时,我可以看到其中一个线程的 QNode 已锁定设置为 false,但我猜这是因为调试器导致缓存更新。我只是将“易失性”扔到所有变量上,绝望地尝试无济于事。这是我正在使用的类:
class MCSLock
{
private volatile AtomicReference<QNode> tail;
private volatile ThreadLocal<QNode> myNode;
public MCSLock()
{
tail = new AtomicReference<QNode>(null);
myNode = new ThreadLocal<QNode>()
{
protected QNode initialValue() { return new QNode(); }
};
}
public void lock()
{
QNode qnode = myNode.get();
QNode pred = tail.getAndSet(qnode);
if (pred != null)
{
qnode.locked = true;
pred.next = qnode;
while (qnode.locked);
}
}
public void unlock()
{
QNode qnode = myNode.get();
if (qnode.next == null)
{
if (tail.compareAndSet(qnode, null)) return;
while (qnode.next == null);
}
qnode.next.locked = false;
qnode.next = null;
}
private class QNode
{
volatile boolean locked = false;
volatile QNode next = null;
}
}
【问题讨论】:
-
如果您将
QNode更改为使用AtomicBoolean和AtomicReference是否有效? -
我对 Java 中的并发性知之甚少,无法自信地说出发生了什么,我怀疑几乎所有 SO 上的人都是如此。您可能希望将其发送到 concurrency-interest 邮件列表,Java 并发世界的伟大与美好汇聚于此。
-
@msandiford 遗憾的是,它没有:(
-
刚刚测试过,它对我来说工作正常,最多 10 个线程。您也可以发布失败的测试代码吗?你用的是哪个JDK?
-
@msandiford 我的测试代码相当长,但这是一般的想法:使用 n 个线程计数 1 到 1200000,其中 n 从 1 到 6。如果您不使用大数字,或者您没有足够的争用,那么代码可能会起作用。这里的想法是确保它在压力下工作。
标签: java multithreading caching locking volatile