Map的线程安全获取和放置方法(性能测试)

时间:2013-02-01 19:03:04

标签: java multithreading performance-testing

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

我正在进行更新并获取地图的方式将是线程安全的。对?因为我发现很难调试这个Mutltithreading程序,看看我的程序是否正常工作。任何人都可以帮我解决这个多线程程序

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);
    }
}

任何人都可以看一下,让我知道这次我是否做对了?

3 个答案:

答案 0 :(得分:2)

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

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

如果您需要无锁解决方案,请使用ConcurrentHashMap<Long, AtomicLong>并使用此代码进行更新:

final Long before = histogram.putIfAbsent(difference, new AtomicLong(1L));
if (before != null) before.incrementAndGet();

答案 1 :(得分:1)

您不需要使用ConcurrentHashMap同步

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

答案 2 :(得分:1)

查看番石榴的AtomicLongMap