Warm tip: This article is reproduced from serverfault.com, please click

java-当AtomicInteger比同步快时

(java - When AtomicInteger is faster than synchronized)

发布于 2020-12-06 21:23:30

我已经读了很多文章,据说AtomicInteger类比同步构造工作得更快。我在AtomicInteger上进行了一些测试,并进行了“同步”,在我的测试中,发现同步比AtomicInteger快得多。我想了解出了什么问题:我的测试类不正确,或者在其他情况下AtomicInteger的工作速度更快?

这是我的测试课:

    public class Main {

    public static void main(String[] args) throws InterruptedException
    {
        // creating tester "synchronized" class
        TesterSynchronized testSyn = new TesterSynchronized();

        // Creating 3 threads
        Thread thread1 = new Thread(testSyn);
        Thread thread2 = new Thread(testSyn);
        Thread thread3 = new Thread(testSyn);

        // start time
        long beforeSyn = System.currentTimeMillis();

        // start
        thread1.start();
        thread2.start();
        thread3.start();

        thread1.join();
        thread2.join();
        thread3.join();

        long afterSyn = System.currentTimeMillis();
        long delta = afterSyn - beforeSyn;

        System.out.println("Test synchronized: " + delta + " ms");

        // _______________________________________________________

        // creating tester "atomicInteger" class
        TesterAtomicInteger testAtomic = new TesterAtomicInteger();

        thread1 = new Thread(testAtomic);
        thread2 = new Thread(testAtomic);
        thread3 = new Thread(testAtomic);

        // start time
        long beforeAtomic = System.currentTimeMillis();

        // start
        thread1.start();
        thread2.start();
        thread3.start();

        thread1.join();
        thread2.join();
        thread3.join();

        long afterAtomic = System.currentTimeMillis();
        long deltaAtomic = afterAtomic - beforeAtomic;

        System.out.println("Test atomic integer: " + deltaAtomic + " ms");
    }
}

// Synchronized tester
class TesterSynchronized implements Runnable {
    public int integerValue = 0;

    public synchronized void run() {
        for (int i = 0; i < 1_000_000; i++)
            integerValue++;
    }
}

// AtomicInteger class tester
class TesterAtomicInteger implements Runnable {
    AtomicInteger atomicInteger = new AtomicInteger(0);

    public void run() {
        for (int i = 0; i < 1_000_000; i++)
            atomicInteger.incrementAndGet();
    }
}

测试参数:3个线程,增量为1_000_000;结果:

测试同步:7毫秒。测试原子整数:51毫秒

我很高兴了解为什么会这样。

UPD 如果将同步方法更改为同步块,则测试将是正确的

// Synchronized tester
class TesterSynchronized implements Runnable {
    public int integerValue = 0;

    public void run() {
        for (int i = 0; i < 1_000_000; i++) {
            synchronized (this) {
                integerValue++;
            }
        }
    }
}
Questioner
gurmigou
Viewed
0
Tom Hawtin - tackline 2020-12-07 05:34:53

你的代码中明显的不同之处在于,该AtomicIntger版本允许对具有访问权限的线程进行交织,而该synchronized版本则依次轮流执行每个线程的整个循环。

可能还有其他问题。例如,JVM可以合并一个synchronized块的多个调用根据平台的不同,incrementAndGet可能不是原子操作,而是实现为CAS循环-如果争用很高,则可能是个问题(对此我不完全确定)。

无论采用哪种排列方式,如果你有多个线程同时修改同一个内存位置,它将不会很快。