3

我通过比较同步方法测试了多线程中的原子整数有多快,但我得到的结果是原子整数比同步方法慢。

我阅读了 Java API Reference 并且我了解 Atomic Integer 比多线程中的同步更快。

所以我想知道为什么我用 Atomic Integer 得到了不好的结果。我的测试代码错了?

这是我的代码

import java.util.concurrent.atomic.AtomicInteger;

public class AtomicThreadTest {

    // Number of thread to run
    private static final int THREAD_NUM = 1000;
    // Repetition number to count up
    private static final int ROOP_NUM = 200000;

    // Base counter class
    private abstract class Counter implements Runnable {
        @Override
        public void run() {
            for (int i = 0; i < ROOP_NUM; i++) {
                increment();
            }
        }
        // Increment method
        public abstract void increment();
        // Get result of calculation
        public abstract int getResult();
        // Get name of the class
        @Override
        public String toString() {
            return getClass().getSimpleName();
        }
    }

    // Use no thread safe
    private static int count = 0;
    private class NoThreadSafeCounter extends Counter {
        @Override
        public void increment() {
            count++;
        }
        @Override
        public int getResult() {
            return count;
        }
    }

    // Use volatile
    private static volatile int volatileCount = 0;
    private class VolatileCounter extends Counter {
        @Override
        public void increment() {
            volatileCount++;
        }
        @Override
        public int getResult() {
            return volatileCount;
        }
    }

    // Use synchronized
    private static int synchronizedCount = 0;
    private class SynchronizedCounter extends Counter {
        @Override
        public synchronized void increment() {
            synchronizedCount++;
        }
        @Override
        public int getResult() {
            return synchronizedCount;
        }
    }

    // Use AtomicInteger
    private static AtomicInteger atomicCount = new AtomicInteger(0);
    private class AtomicCounter extends Counter {
        @Override
        public void increment() {
            atomicCount.incrementAndGet();
        }
        @Override
        public int getResult() {
            return atomicCount.get();
        }
    }

    public static void main(String[] args) {
        AtomicThreadTest testClass = new AtomicThreadTest();
        Counter[] testCounter = {
                testClass.new NoThreadSafeCounter(),
                testClass.new VolatileCounter(),
                testClass.new SynchronizedCounter(),
                testClass.new AtomicCounter(),
        };

        for (Counter c : testCounter) {
            System.out.println("-------------------------");
            System.out.printf("Test for class : %s\n", c.toString());
            try {
                test(c);
            } catch (InterruptedException e) {
                System.out.println("Test halted");
            } finally {
                System.out.println("");
                System.gc();
            }
        }
        System.out.println("-------------------------");
    }

    public static void test(final Counter counter) throws InterruptedException {
        System.out.printf("Start with threads : %d, roop : %d\n", THREAD_NUM, ROOP_NUM);
        final long startTime = System.currentTimeMillis();

        // Create THREAD_NUM threads and run them
        Thread[] threads = new Thread[THREAD_NUM];

        for (int i = 0; i < THREAD_NUM; i++) {
            threads[i] = new Thread(counter);
            threads[i].start();
        }

        // Wait for all threads other than this end
        while (Thread.activeCount() > 1) {
            Thread.sleep(10);
        }

        final long endTime = System.currentTimeMillis();
        System.out.printf("Result %d, Expected %d\n", counter.getResult(), THREAD_NUM*ROOP_NUM);
        System.out.printf("Time to calc : %d\n", endTime-startTime);
    }
}

我得到了下面的结果。

-------------------------
Test for class : NoThreadSafeCounter
Start with threads : 1000, roop : 200000
Result 198785583, Expected 200000000
Time to calc : 127

-------------------------
Test for class : VolatileCounter
Start with threads : 1000, roop : 200000
Result 19162116, Expected 200000000
Time to calc : 4458

-------------------------
Test for class : SynchronizedCounter
Start with threads : 1000, roop : 200000
Result 200000000, Expected 200000000
Time to calc : 8426

-------------------------
Test for class : AtomicCounter
Start with threads : 1000, roop : 200000
Result 200000000, Expected 200000000
Time to calc : 15190
4

1 回答 1

2

尽管您的测试用例存在代码问题,让我们谈谈多线程问题本身。

如果你设置THREAD_NUM一个低得多的数字,比如 8 或 4,你会发现你AtomicCounter的速度比SynchronizedCounter. 使用 1000 个线程运行将在 CAS(比较和交换)上花费两个 CPU AtomicInteger,这会导致它的运行速度比synchronized代码块慢。

为了证明这一点,您可以实现LongadderCounter

private class LongadderCounter extends Counter {

    @Override
    public void increment() {
        longadder.increment();
    }

    @Override
    public int getResult() {
        return longadder.intValue();
    }
}

你会发现LongadderCounter要快得多。LongAddertoAtomicIntegerConcurrentHashMapto Collections.synchronizedMap(new HashMap<>()),它将计数器分成多个部分,并对每个部分进行 CAS 以缓解竞争条件。

于 2015-09-06T12:13:13.973 回答