我有一个只有一个编写线程的应用程序,它可以做一些事情并更新一些度量指标,例如计数器等。这个应用程序有许多其他线程,它们读取统计数据并使用它们进行操作。这些指标必须是最新的,这并不重要,但是编写线程需要尽可能少的时间被阻塞。我想知道下列哪一项更适合我的需要:
选项1-有一个只有写入器才能更新的非原子字段和一个使用AtomicXXX设置的lazySet字段
class Stats1
{
private final AtomicLong someCounterAtomic = new AtomicLong(0);
private long someCounter = 0;
// writer thread updates the stats using this
public void incrementCounter(long counterIncrement)
{
someCounter += counterIncrement;
someCounterAtomic.lazySet(someCounter);
}
// reader threads call this
public long getCounterValue()
{
return someCounterAtomic.get();
}
}选项2-只有一个通过AtomicXXX更新的addAndGet字段
class Stats2
{
private final AtomicLong someCounter = new AtomicLong(0);
// writer thread updates the stats using this
public void incrementCounter(long counterIncrement)
{
someCounter.addAndGet(counterIncrement);
}
// reader threads call this
public long getCounterValue()
{
return someCounter.get();
}
}还是我还是做点别的更好?
提前谢谢。
发布于 2014-08-19 18:08:41
如果有些最近的统计是好的,我不会同步任何东西。我会让作者的线程定期拍摄快照,并通过原子引用定期(或在统计数据发生足够大的变化之后)发布。
public class Stats {
// the currently available stat instance
public static AtomicReference<Stats> CURRENT_STATS =
new AtomicReference<>(new Stats());
private final int whatever1;
private final int whatever2;
private Stats() {
this(0, 0);
}
public Stats(int whatever1, int whatever2) {
this.whatever1 = whatever1;
...
}
public int getWhatever1() {
return whatever1;
}
public int getWhatever2() {
return whatever2;
}
}作者只是在认为合适时创建一个新的Stats实例,并设置CURRENT_STATS引用。读者只需在需要统计数据时阅读引用,并将引用保持到当前处理传递完成为止(避免在处理时更改统计数据)。
这需要最低限度的同步,当对统计数据的最新需求比较宽松时(例如,向用户显示吞吐量等),这是合适的。不管Stats公开了多少变量,一个原子引用都可以控制它们。
发布于 2014-08-19 17:09:55
只需使用addAndGet。它很简单,可以立即识别,而且很可能足够快。
如果只有一个线程更新计数器,那么addAndGet是没有争议的,并且将与您的Stats1代码一样快。如果有多个线程在更新,那么Stats1就是完全错误的。无论哪种方式,您都不应该使代码复杂化,除非您有基准测试/分析数据,这表明这对您的应用程序的总体运行时间来说是一个很大的成本。
发布于 2014-08-19 18:40:13
如果您使用的是Java 8,则应该考虑java.util.concurrent.atomic中的java.util.concurrent.atomic类:
当多个线程更新一个用于收集统计信息,而不是用于细粒度同步控制的公共和时,这个类通常比AtomicLong更好。在低更新争用条件下,两类具有相似的特性。但是在竞争激烈的情况下,这类的预期吞吐量要高得多,而牺牲了更高的空间消耗。
请注意,如果您遵循“永不同步”这一公认的答案中的建议,那么统计数据可能永远不会更新(取决于您的程序中还发生了什么,运行的是哪个体系结构,哪个Java等等)。
https://stackoverflow.com/questions/25388989
复制相似问题