0

我正在尝试对我的服务进行一些性能测试。所以我为此编写了一个多线程程序。它将以很少的线程并行访问我的服务,然后测量每个线程返回所需的时间。

我进行更新并进入地图的方式将是线程安全的。正确的?因为我发现很难调试这个多线程程序来查看我的程序是否正常工作。谁能帮我解决这个多线程程序

private static ConcurrentHashMap<Long, Long> histogram = new ConcurrentHashMap<Long, Long>();

    public static void main(String[] args) {

        ExecutorService service = Executors.newFixedThreadPool(10);

        for (int i = 0; i < 1 * 1000; i++) {
            service.submit(new ThreadTask(i, histogram));
        }

        service.shutdown();

        while (!service.isTerminated()) {

        }

        ThreadTask.report();
    }


class ThreadTask implements Runnable {
    private int id;
    private RestTemplate restTemplate = new RestTemplate();
    private String result;
    private static ConcurrentHashMap<Long, Long> mapData;

    public ThreadTask(int id, ConcurrentHashMap<Long, Long> histogram) {
        this.id = id;
        this.mapData = histogram;
    }

    @Override
    public void run() {

            long start_time = System.currentTimeMillis();

            result = restTemplate.getForObject("",  String.class);
            long difference = (System.currentTimeMillis() - start_time);

            Long count = getMethod(mapData, difference);
            if (count != null) {
                count++;
                putMethod(mapData, difference, count);
            } else {
                putMethod(mapData, difference, Long.valueOf(1L));
            }

    }

    private synchronized void putMethod(ConcurrentHashMap<Long, Long> hg2, long difference, Long count) {
        hg2.put(Long.valueOf(difference), count);       
    }

    private synchronized Long getMethod(ConcurrentHashMap<Long, Long> hg2, long difference) {
        return hg2.get(difference);
    }

    public static void report() {
        System.out.println(mapData);
    }
}

根据以下建议更新了代码 -

    private static RestTemplate restTemplate = new RestTemplate();
    private static String result = null;
    private static ConcurrentHashMap<Long, AtomicLong> histogram = new ConcurrentHashMap<Long, AtomicLong>();

    public static void main(String[] args) {

        ExecutorService service = Executors.newFixedThreadPool(10);

        for (int i = 0; i < 1 * 1000; i++) {
            service.submit(new ThreadTask(i, histogram));
        }

        service.shutdown();

        while (!service.isTerminated()) {

        }

        ThreadTask.report();
    }


class ThreadTask implements Runnable {
    private int id;
    private static RestTemplate restTemplate = new RestTemplate();
    private String result;
    private static ConcurrentHashMap<Long, AtomicLong> hg;

    public ThreadTask(int id, ConcurrentHashMap<Long, AtomicLong> histogram) {
        this.id = id;
        this.hg = histogram;
    }

    @Override
    public void run() {

            long start_time = System.currentTimeMillis();

            result = restTemplate.getForObject("",  String.class);
            long difference = (System.currentTimeMillis() - start_time);

        final AtomicLong before = hg.putIfAbsent(difference, new AtomicLong(1L));
        if (before != null) {
            before.incrementAndGet();
        }

    }

    public static void report() {
        System.out.println(mapData);
    }
}

谁能看一下,让我知道这次我做对了吗?

4

3 回答 3

2

不,您的代码绝对不是线程安全的,因为整个更新操作不是原子的。你读取一个值,增加它,然后写回。到那时,另一个线程可能已经增加了相同的直方图条目,现在您正在保存一个陈旧的值,有效地“吞下”了一个命中。

我的建议:synchronized (histogram) { ... }围绕整个更新操作使用。但是,您不需要单独的同步方法。

如果您想要一个无锁解决方案,请使用ConcurrentHashMap<Long, AtomicLong>并使用此代码来更新它:

final Long before = histogram.putIfAbsent(difference, new AtomicLong(1L));
if (before != null) before.incrementAndGet();
于 2013-02-01T19:16:54.990 回答
1

您不需要将同步与 ConcurrentHashMap 一起使用

您应该通过多次运行代码来预热代码。我会忽略前 10,000 次并运行测试至少 2 到 10 秒。

于 2013-02-01T19:07:46.437 回答
1

查看 Guava 的AtomicLongMap

于 2013-02-01T23:38:31.017 回答