Java codahale metrics Meter mark()方法的线程安全性如何?

Java codahale metrics Meter mark()方法的线程安全性如何?,java,multithreading,dropwizard,metrics,codahale-metrics,Java,Multithreading,Dropwizard,Metrics,Codahale Metrics,我最近开始学习CodaHale/DropWizard度量库。我无法理解Meter类线程是如何安全的(根据文档),尤其是mark()和TickIfEssential()方法: 谢谢 玛丽安在我看来,你是对的。如果调用tickifsemdable(),使得age>TICK\u INTERVAL在另一个调用仍在运行时,则可能会从多个线程同时调用m1Rate.TICK()和其他TICK()方法。因此,它可以归结为tick()及其调用的例程/操作是否安全 让我们仔细分析一下tick(): alpha和i

我最近开始学习CodaHale/DropWizard度量库。我无法理解Meter类线程是如何安全的(根据文档),尤其是mark()和TickIfEssential()方法:

谢谢


玛丽安

在我看来,你是对的。如果调用
tickifsemdable()
,使得
age>TICK\u INTERVAL
在另一个调用仍在运行时,则可能会从多个线程同时调用
m1Rate.TICK()
和其他
TICK()
方法。因此,它可以归结为
tick()
及其调用的例程/操作是否安全

让我们仔细分析一下
tick()

alpha
interval
仅在实例初始化时设置,并标记为final那些自只读以来线程安全的
count
instantRate
是本地的,其他线程无论如何都看不到<代码>速率和
初始化
被标记为易失性,并且这些写入操作在以下读取中应始终可见

如果我没有错的话,从第一次读取
initialized
到最后一次写入
initialized
rate
这对争用是开放的,但有些是无效的,比如当两个线程争用
initialized
切换到
true

似乎大多数有效的竞争都可以发生在
rate+=(alpha*(instantate-rate))特别是删除或混合计算,如:

  • 假设:
    已初始化
  • 线程1:计算
    计数
    实例化
    ,检查
    初始化
    ,第一次读取我们称之为
    上一次速率
    速率
    ,并因任何原因暂停
  • 线程2:计算
    计数
    实例化
    ,检查
    初始化
    ,并计算
    速率+=(alpha*(实例化-速率))
  • Thread1:继续其操作并计算
    rate+=(alpha*(instantRate-previous_rate))
  • 如果读取和写入以某种方式进行排序,从而在所有线程上读取
    rate
    ,然后在所有线程上写入,则会发生删除,从而有效地删除一个或多个计算

    但是这种竞争的概率,意味着两个
    age>TICK\u INTERVAL
    匹配,使得两个线程运行到相同的
    TICK()
    方法,尤其是
    rate+=(alpha*(instantRate-rate))
    可能非常低,这取决于不明显的值

    只要对
    更新
    /
    添加
    sumThenReset
    中的
    勾选()
    方法使用线程安全的数据结构,那么
    标记()方法似乎是线程安全的


    我认为唯一能够回答悬而未决的问题的人是项目作者或对项目的这些部分和计算出的值有深入了解的人,无论这些竞赛是否没有明显的影响或以其他方式减轻影响。

    这是线程安全的,因为这一行来自
    tickiffessed()
    newIntervalsStartTick

    if (lastTick.compareAndSet(oldTick, newIntervalStartTick))
    
    如果两个线程几乎同时输入
    tickiffessful()
    ,会发生什么情况

    两个线程从
    oldTick
    读取相同的值,确定至少已过
    TICK\u间隔
    纳秒,并计算
    newIntervalStartTick

    现在两个线程都尝试执行
    lastTick.compareAndSet(oldTick,newIntervalStartTick)
    。正如名称
    compareAndSet
    所示,此方法将当前值
    lastTick
    oldTick
    进行比较,并且仅当该值等于
    oldTick
    时,它才会自动替换为
    newIntervalStartTick
    ,并返回true

    由于这是一条原子指令(在硬件级别!),因此只有一个线程可以成功。当另一个线程执行此方法时,它将看到
    newIntervalStartTick
    作为
    lastTick
    的当前值。由于此值不再与
    oldTick
    匹配,更新失败,方法返回false,因此此线程不会调用
    m1Rate.tick()
    m15Rate.tick()


    EWMA.update(n)
    方法使用一个
    java.util.concurrent.atomic.longader
    来累积事件计数,从而提供类似的线程安全保证。

    感谢您,到目前为止,我将保持它的打开状态,因此,作者中的某些人可能会注意到这一点。好的,如果由于某种原因,线程将在比较数据集之后挂起/等待if部分,然后会出现另一个勾号。在比较数据集之后,另一个线程也将进入if部件。我的意思是这不太可能,但可能。对吗?你能回答我的评论吗?谢谢。这是可能发生的,但不太可能,因为滴答声每五秒钟发生一次。
    public void tick() {
        final long count = uncounted.sumThenReset();
        final double instantRate = count / interval;
        if (initialized) {
            rate += (alpha * (instantRate - rate));
        } else {
            rate = instantRate;
            initialized = true;
        }
    }
    
    public void tick() {
        final long count = uncounted.sumThenReset();
        final double instantRate = count / interval;
        if (initialized) {
            rate += (alpha * (instantRate - rate));
        } else {
            rate = instantRate;
            initialized = true;
        }
    }
    
    if (lastTick.compareAndSet(oldTick, newIntervalStartTick))