我有一个Metrics类,它应该跟踪我们每秒处理多少个事务以及它们需要多长时间。其结构的相关部分看起来是这样的:多个变量之间的java线程安全
public class Metrics {
AtomicLong sent = new AtomicLong();
AtomicLong totalElapsedMsgTime = new AtomicLong();
AtomicLong sentLastSecond = new AtomicLong();
AtomicLong avgTimeLastSecond = new AtomicLong();
public void outTick(long elapsedMsgTime){
sent.getAndIncrement();
totalElapsedMsgTime.getAndAdd(elapsedMsgTime);
}
class CalcMetrics extends TimerTask {
@Override
public void run() {
sentLastSecond.set(sent.getAndSet(0));
long tmpElapsed = totalElapsedMsgTime.getAndSet(0);
long tmpSent = sentLastSecond.longValue();
if(tmpSent != 0) {
avgTimeLastSecond.set(tmpElapsed/tmpSent);
} else {
avgTimeLastSecond.set(0);
}
}
}
}
我的问题是,outTick函数将被调用上百次从许多不同的线程中的第二。 AtomicLong已经确保每个变量都是单独的线程安全,并且它们不会在该函数中彼此交互,所以我不希望一个锁会让一个调用outTick阻塞另一个线程调用outTick。如果有几个不同的线程递增发送的变量,然后它们都添加到totalElapsedMsgTime变量中,那就很好了。
但是,一旦进入CalcMetrics运行方法(它只发生一次每秒一次),它们就会做交互。我希望确保能够在不进行outTick调用的情况下重置这两个变量,或者在接收一个变量和下一个变量之间发生另一个outTick调用。
有没有办法做到这一点? (我的解释是否有意义?)有没有办法说A不能与B交错,但是多个B可以相互交错?
编辑:
我去,詹姆斯建议ReadWriteLock中。以下是我对任何感兴趣的人的结果:
public class Metrics {
AtomicLong numSent = new AtomicLong();
AtomicLong totalElapsedMsgTime = new AtomicLong();
long sentLastSecond = 0;
long avgTimeLastSecond = 0;
private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
private final Lock readLock = readWriteLock.readLock();
private final Lock writeLock = readWriteLock.writeLock();
public void outTick(long elapsedMsgTime) {
readLock.lock();
try {
numSent.getAndIncrement();
totalElapsedMsgTime.getAndAdd(elapsedMsgTime);
}
finally
{
readLock.unlock();
}
}
class CalcMetrics extends TimerTask {
@Override
public void run() {
long elapsed;
writeLock.lock();
try {
sentLastSecond = numSent.getAndSet(0);
elapsed = totalElapsedMsgTime.getAndSet(0);
}
finally {
writeLock.unlock();
}
if(sentLastSecond != 0) {
avgTimeLastSecond = (elapsed/sentLastSecond);
} else {
avgTimeLastSecond = 0;
}
}
}
}
谢谢。这看起来像我在找什么。在我的特定用例中,“读取”和“写入”有点用词不当,因为我希望在更新它们时使用并发性(并因此使用ReaderLock),并在收集结果时使用专用WriterLock,但至少ReadWriteLock用相同的变量来解决排他性和并发区域两方面的问题。 (我对这种语言仍然很陌生 - 非常需要学习。) – Lesley
@Lesley,有时它也被称为“共享/排他”锁。 –