AtomicInteger比同步慢

时间:2015-09-06 10:17:45

标签: java synchronized atomicinteger

我通过比较同步方法来测试多线程中Atomic Integer的速度有多快,但我得到的结果是Atomic Integer比同步方法慢。

我阅读了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

1 个答案:

答案 0 :(得分:2)

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

如果您将AtomicInteger设置为更低的数字(例如8或4),您会发现synchronizedLongadderCounter快一点。使用1000个线程运行将花费private class LongadderCounter extends Counter { @Override public void increment() { longadder.increment(); } @Override public int getResult() { return longadder.intValue(); } } 的CAS(比较和交换)上的两个CPU,这导致它比LongadderCounter代码块运行得慢。

为了证明这一点,您可以实施LongAdder

AtomicInteger

您会更快地发现ConcurrentHashMapCollections.synchronizedMap(new HashMap<>()) var usrInput = usrInput.ToLower(); foreach(var letter in usrInput) { if (letter == 'a' || letter == 'b' || letter == 'c') { Console.Write("1"); } else if (letter == 'd' || letter == 'e' || letter == 'f') { Console.Write("2"); } else if (letter == 'g' || letter == 'h' || letter == 'i') { Console.Write("3"); } } dataimport.propertiesUTC,它将计数器分为多个部分,并在每个部分执行CAS以减轻竞争条件。