一道javaSE编程题求大神指点

统计网站访问量,要求实现Count接口,hr方法多线程访问,要保证线程安全


要求:

  • 1.实现功能
  • 2.线程安全
  • 3.注意性能
interface Count {
    //每访问一次hr方法+1
    void hr();
    //访问状态
    DateState state();
}

class DateState {
    //最近10秒钟平均访问量
    public int last10Second;
    //最近60秒钟平均访问量
    public int last60Second;
    //最近10分钟平均访问量
    public int last10Minute;
    //最近60分钟平均访问量
    public int last60Minute;
    //60分钟平均访问量集合
    public List<Integer> last60SecondList;
}

不知道该如何计算最近时间段里的平均访问量,希望大神点拨,小弟在此感激不尽

解题思路


先说下思路,这道题的难点在于如何获取指定时间段内的数据,在百度知识中经过一位大神提点,在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]