Replace AtomicInteger with LongAdder for curThreadNum of StatisticNode (#747)

This commit is contained in:
Lin.Liang 2019-06-04 17:51:36 +08:00 committed by Eric Zhao
parent 9583e18706
commit 3a9e2629b7
2 changed files with 137 additions and 10 deletions

View File

@ -15,15 +15,15 @@
*/
package com.alibaba.csp.sentinel.node;
import com.alibaba.csp.sentinel.node.metric.MetricNode;
import com.alibaba.csp.sentinel.slots.statistic.base.LongAdder;
import com.alibaba.csp.sentinel.slots.statistic.metric.ArrayMetric;
import com.alibaba.csp.sentinel.slots.statistic.metric.Metric;
import com.alibaba.csp.sentinel.util.TimeUtil;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import com.alibaba.csp.sentinel.util.TimeUtil;
import com.alibaba.csp.sentinel.node.metric.MetricNode;
import com.alibaba.csp.sentinel.slots.statistic.metric.ArrayMetric;
import com.alibaba.csp.sentinel.slots.statistic.metric.Metric;
/**
* <p>The statistic node keep three kinds of real-time statistics metrics:</p>
@ -104,7 +104,7 @@ public class StatisticNode implements Node {
/**
* The counter for thread count.
*/
private AtomicInteger curThreadNum = new AtomicInteger(0);
private LongAdder curThreadNum = new LongAdder();
/**
* The last timestamp when metrics were fetched.
@ -233,7 +233,7 @@ public class StatisticNode implements Node {
@Override
public int curThreadNum() {
return curThreadNum.get();
return (int)curThreadNum.sum();
}
@Override
@ -265,12 +265,12 @@ public class StatisticNode implements Node {
@Override
public void increaseThreadNum() {
curThreadNum.incrementAndGet();
curThreadNum.increment();
}
@Override
public void decreaseThreadNum() {
curThreadNum.decrementAndGet();
curThreadNum.decrement();
}
@Override

View File

@ -17,17 +17,23 @@ package com.alibaba.csp.sentinel.node;
import com.alibaba.csp.sentinel.Constants;
import com.alibaba.csp.sentinel.util.TimeUtil;
import org.junit.Assert;
import org.junit.Test;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@ -198,4 +204,125 @@ public class StatisticNodeTest {
private static void log(Object obj) {
System.out.println(LOG_PREFIX + obj);
}
/**
* com.alibaba.csp.sentinel.node.StatisticNode#curThreadNum using LongAdder replace the AtomicInteger.
* now test the LongAdder is fast than AtomicInteger
* and get the right statistic or not
*/
@Test
public void testStatisticLongAdder() throws InterruptedException {
AtomicInteger atomicInteger = new AtomicInteger(0);
StatisticNode statisticNode = new StatisticNode();
ExecutorService bizEs1 = new ThreadPoolExecutor(THREAD_COUNT, THREAD_COUNT,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
ExecutorService bizEs2 = new ThreadPoolExecutor(THREAD_COUNT, THREAD_COUNT,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
int taskCount = 100;
for (int i = 0; i < taskCount; i++) {
int op = i % 2;
bizEs2.submit(new StatisticAtomicIntegerTask(atomicInteger, op, i));
bizEs1.submit(new StatisticLongAdderTask(statisticNode, op, i));
}
Thread.sleep(5000);
log("LongAdder totalCost : " + StatisticLongAdderTask.totalCost() + "ms");
log("AtomicInteger totalCost : " + StatisticAtomicIntegerTask.totalCost() + "ms");
Assert.assertEquals(statisticNode.curThreadNum(), atomicInteger.get());
}
private static class StatisticLongAdderTask implements Runnable {
private StatisticNode statisticNode;
/**
* 0 addition
* 1 subtraction
*/
private int op;
private int taskId;
private static Map<Integer, Long> taskCostMap = new ConcurrentHashMap<>(16);
public StatisticLongAdderTask(StatisticNode statisticNode, int op, int taskId) {
this.statisticNode = statisticNode;
this.op = op;
this.taskId = taskId;
}
@Override
public void run() {
long startTime = System.currentTimeMillis();
int calCount = 100000;
for (int i = 0; i < calCount; i++) {
if (op == 0) {
statisticNode.increaseThreadNum();
} else if (op == 1) {
statisticNode.decreaseThreadNum();
}
}
long cost = System.currentTimeMillis() - startTime;
taskCostMap.put(taskId, cost);
}
public static long totalCost() {
long totalCost = 0;
for (long cost : taskCostMap.values()) {
totalCost += cost;
}
return totalCost;
}
}
private static class StatisticAtomicIntegerTask implements Runnable {
AtomicInteger atomicInteger;
/**
* 0 addition
* 1 subtraction
*/
private int op;
private int taskId;
private static Map<Integer, Long> taskCostMap = new ConcurrentHashMap<>(16);
public StatisticAtomicIntegerTask(AtomicInteger atomicInteger, int op, int taskId) {
this.atomicInteger = atomicInteger;
this.op = op;
this.taskId = taskId;
}
@Override
public void run() {
long startTime = System.currentTimeMillis();
int calCount = 100000;
for (int i = 0; i < calCount; i++) {
if (op == 0) {
atomicInteger.incrementAndGet();
} else if (op == 1) {
atomicInteger.decrementAndGet();
}
}
long cost = System.currentTimeMillis() - startTime;
taskCostMap.put(taskId, cost);
}
public static long totalCost() {
long totalCost = 0;
for (long cost : taskCostMap.values()) {
totalCost += cost;
}
return totalCost;
}
}
}