java - AtomicInteger 比同步慢

标签 java synchronized atomicinteger

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

我阅读了 Java API 引用,我了解到 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

最佳答案

抛开你的测试用例的代码问题,让我们谈谈多线程问题本身。

如果你设置THREAD_NUM到更小的数字,例如 8 或 4,您会发现您的 AtomicCounterSynchronizedCounter 快一点.在 AtomicInteger 上运行 1000 个线程将花费两倍的 CPU的 CAS(比较和交换),这导致它运行得比 synchronized 慢代码块。

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

private class LongadderCounter extends Counter {

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

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

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

关于java - AtomicInteger 比同步慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32422441/

相关文章:

java - Spring Boot 中的多线程 cron 作业

java - 如何使用 Java API 在 Neo4j 中的节点/关系上添加用户定义的约束

java - 运行 mapreduce 程序时出现 "Java Heap space Out Of Memory Error"

java - 嵌套同步块(synchronized block)

java - AtomicInteger.compareAndSet 返回原始值,而不是 boolean 值

java - 在 facebook 墙上发帖总是显示登录页面..问题 android

java - 为什么 `synchronized` 对于变量来说是非法的?

java - 除非添加打印语句,否则线程同步不起作用

java - 一些 AtomicInteger 方法的实际例子

metal - 如何在 Metal 片段着色器中实现/使用原子计数器?