0

サービスのパフォーマンステストを実行しようとしています。そこで、そのためのマルチスレッドプログラムを作成しました。いくつかのスレッドで並行してサービスにアクセスし、各スレッドが戻るのにかかる時間を測定します。

私が更新を行ってマップに乗る方法はスレッドセーフになります。右?この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);
    }
}

誰かが見て、今回私がそれを正しくしたかどうか私に知らせてもらえますか?

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

Synchronized with ConcurrentHashMap を使用する必要はありません

コードを何度も実行してウォームアップする必要があります。最初の 10,000 回は無視して、少なくとも 2 ~ 10 秒間テストを実行します。

于 2013-02-01T19:07:46.437 に答える
1

Guava のAtomicLongMapを確認してください。

于 2013-02-01T23:38:31.017 に答える