Metrics学习02 – Counter

栏目: Java · 发布时间: 5年前

内容简介:Counter是要学习的Metrics的第二个工具,顾名思义即是计数器,通常用来执行统计之类的工作。Counter比Gauge也复杂不了多少,直接看代码好了:这里的代码较Gauge的那段稍稍有些不同:主要是在Counter实例的创建上 —— 这里使用了MetricRegistry实例的一个工具方法

Counter是要学习的Metrics的第二个工具,顾名思义即是计数器,通常用来执行统计之类的工作。

Counter比Gauge也复杂不了多少,直接看代码好了:

public class CounterShow {
 
    public static void main(String[] args) {
 
        final MetricRegistry metrics = new MetricRegistry();
        final ConsoleReporter reporter = ConsoleReporter.forRegistry(metrics).build();
        reporter.start(3, TimeUnit.SECONDS);
 
        Counter counter = metrics.counter("异常监控");
 
        for (int i = 0; i < 100; i++) {
            try {
                if (0 == i % 3) {
                    throw new RuntimeException("自定义异常");
                }
                TimeUnit.SECONDS.sleep(1);
            } catch (Exception e) {
                counter.inc();
            }
        }
    }
}

这里的代码较Gauge的那段稍稍有些不同:主要是在Counter实例的创建上 —— 这里使用了MetricRegistry实例的一个 工具 方法 counter ( )

MetricRegistry的实例为各种指标工具都提供了快速创建实例的方法,通过MetricRegistry提供的方法创建完成指标实例后可以自动完成注册。所以在上面的代码中没有再显式地将counter实例注册到MetricRegistry中。

另外值得细细品一下的是Counter的实现:Counter的计数能力主要依赖LongAdder类完成。

一般执行计数统计,最先想到的是AtomicLong/AtomicInt类。AtmoicXXX使用硬件级别的指令 CAS 来更新计数器的值,这样可以避免加锁,机器直接支持的指令,效率也很高。但是AtomicXXX中的 CAS 操作在出现线程竞争时,失败的线程会白白地循环一次,在并发很大的情况下,因为每次CAS都只有一个线程能成功,竞争失败的线程会非常多。失败次数越多,循环次数就越多,很多线程的CAS操作越来越接近 自旋锁(spin lock)。计数操作本来是一个很简单的操作,实际需要耗费的cpu时间应该是越少越好,AtomicXXX在高并发计数时,大量的cpu时间都浪费会在 自旋 上了,这很浪费,也降低了实际的计数效率。

使用LongAdder计数器可以避免这个问题。LongAdder采用了锁分段的思想,每个LongAdder实例都维护了一组计数单元Cell[],并发计数时,不同的线程可以在不同的计数单元cell[threadId]上进行计数,这样减少了线程竞争,提高了并发效率。本质上是用空间换时间的思想。

不过LongAdder一开始并不会直接使用计数单元Cell[],而是先使用一个long类型的base存储,当casBase()出现失败时,则会创建计数单元Cell[]。此时,如果在单个计数单元面出现了更新冲突,那么会尝试创建新的计数单元Cell,或者将Cell[]扩容为2倍。代码如下:

    public void increment() {
        add(1L);
    }
 
    public void add(long x) {
        Cell[] as; long b, v; int m; Cell a;
        if ((as = cells) != null || !casBase(b = base, b + x)) {// 如cells不为空,直接对cells操作;否则casBase
            boolean uncontended = true;
            if (as == null || (m = as.length - 1) < 0 ||
                (a = as[getProbe() & m]) == null ||
                !(uncontended = a.cas(v = a.value, v + x)))    // CAS cell
                longAccumulate(x, null, uncontended);    // 创建新的Cell或者扩容
        }
    }

在高并发的情况下,LongAdder较之AtomicXXX有着数倍的性能优势。因此,通常建议使用LongAdder替换AtomicXXX。

再看下Counter的测试结果:

19-6-24 22:18:37 ===============================================================
-- Counters --------------------------------------------------------------------
异常监控
             count = 2
 
19-6-24 22:18:40 ===============================================================
-- Counters --------------------------------------------------------------------
异常监控
             count = 3
 
19-6-24 22:18:43 ===============================================================
-- Counters --------------------------------------------------------------------
异常监控
             count = 5

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Metasploit渗透测试魔鬼训练营

Metasploit渗透测试魔鬼训练营

诸葛建伟、陈力波、田繁、孙松柏、等 / 机械工业出版社 / 2013-9-1 / 89.00元

首本中文原创Metasploit渗透测试著作,国内信息安全领域布道者和资深Metasploit渗透测试专家领衔撰写,极具权威性。以实践为导向,既详细讲解了Metasploit渗透测试的技术、流程、方法和技巧,又深刻阐释了渗透测试平台背后蕴含的思想。 本书是Metasploit渗透测试领域难得的经典佳作,由国内信息安全领域的资深Metasploit渗透测试专家领衔撰写。内容系统、广泛、有深度,......一起来看看 《Metasploit渗透测试魔鬼训练营》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

URL 编码/解码
URL 编码/解码

URL 编码/解码

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换