解题思路
先说下思路,这道题的难点在于如何获取指定时间段内的数据,在百度知识中经过一位大神提点,在hr方法中统计访问量的时候把当前时间即访问时间添加进集合中,这样就可能以当前时间为开始时间对集合进行反向遍历,开始时间减去访问时间不超过指定时间的,就进行计数,最后得到的即是最近某个时间段的访问量了。
至于某个时间段的访问集合,考虑到性能问题不放在state方法中遍历统计,放在访问的时候就进行统计,因此定义了一个setCount方法,以第一个元素的访问时间作为开始时间开始计数,后续访问时间在指定时间段内统计其数量求平均值放进集合当中。在state方法中直接引用集合即可。
最终代码如下:
这里将60分钟平均访问量集合改成了60秒
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
public class CountImpl implements Count {
private static final long TIME_SLOT_TEN = 10;
private static final long TIME_SLOT_SIXTY = 60;
private static final int INIT_VALUE = 0;
private static final int INCR_VALUE = 1;
private static final long TIME_10S = TimeUnit.SECONDS.toMillis(TIME_SLOT_TEN);
private static final long TIME_60S = TimeUnit.SECONDS.toMillis(TIME_SLOT_SIXTY);
private static final long TIME_10M = TimeUnit.MINUTES.toMillis(TIME_SLOT_TEN);
private static final long TIME_60M = TimeUnit.MINUTES.toMillis(TIME_SLOT_SIXTY);
private AtomicLong count = new AtomicLong();
private AtomicLong start = new AtomicLong();
private CopyOnWriteArrayList<Long> list = new CopyOnWriteArrayList();
private AtomicInteger last60Second = new AtomicInteger();
private CopyOnWriteArrayList<Integer> last60SecondList = new CopyOnWriteArrayList();
@Override
public void hr() {
count.getAndIncrement();
list.add(System.currentTimeMillis());
setCount(System.currentTimeMillis());
}
@Override
public DateState state() {
DateState dateState = new DateState();
long now = System.currentTimeMillis();
int num = INIT_VALUE;
int last10Second = INIT_VALUE;
int last60Second = INIT_VALUE;
int last10Minute = INIT_VALUE;
int last60Minute = INIT_VALUE;
for (int i = list.size() - 1; i >= 0; i--) {
num++;
long time = now - list.get(i);
if (time <= TIME_60M) {
last60Minute = num;
if (time <= TIME_10S) {
last10Second = num;
}
if (time <= TIME_60S) {
last60Second = num;
}
if (time <= TIME_10M) {
last10Minute = num;
}
} else {
break;
}
}
System.out.println("10s内访问总量:" + last10Second);
System.out.println("60s内访问总量" + last60Second);
System.out.println("10m内访问总量" + last10Minute);
System.out.println("60m内访问总量" + last60Minute);
dateState.last10Second = last10Second / (int) TIME_SLOT_TEN;
dateState.last60Second = last60Second / (int) TIME_SLOT_SIXTY;
dateState.last10Minute = last10Minute / (int) TIME_SLOT_TEN;
dateState.last60Minute = last60Minute / (int) TIME_SLOT_SIXTY;
dateState.last60SecondList = last60SecondList;
return dateState;
}
public void setCount(long time) {
if (start.get() == INIT_VALUE) {
start.set(time);
}
if (time - start.get() <= TIME_60S) {
last60Second.set(last60Second.get() + INCR_VALUE);
} else {
last60SecondList.add(last60Second.get() / (int) TIME_SLOT_SIXTY);
System.out.println("最近60秒平均访问量为:" + last60Second.get() + ",平均访问量为:" + last60Second.get() / (int) TIME_SLOT_SIXTY + ",已添加进last60SecondList集合。");
last60Second.set(INIT_VALUE);
start.set(INIT_VALUE);
}
}
}
测试代码
class test {
public static void main(String[] args) {
CountImpl count = new CountImpl();
ExecutorService pool = Executors.newFixedThreadPool(100);
for (int i = 0; i < 1000; i++) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
pool.execute(new Runnable() {
@Override
public void run() {
count.hr();
System.out.println("线程:" + Thread.currentThread().getName() + "正在运行");
}
});
}
pool.shutdown();
DateState state = count.state();
System.out.println("最近10s平均访问量" + state.last10Second);
System.out.println("最近60s平均访问量" + state.last60Second);
System.out.println("最近10m平均访问量" + state.last10Minute);
System.out.println("最近60m平均访问量" + state.last60Minute);
System.out.println("最近60s平均访问量集合" + state.last60SecondList);
}
}
运行结果
10s内访问总量:50
60s内访问总量300
10m内访问总量1000
60m内访问总量1000
最近10s平均访问量5
最近60s平均访问量5
最近10m平均访问量100
最近60m平均访问量16
最近60s平均访问量集合[5, 5, 5]