java - AtomicInteger 与 Java 中的同步 int 变量 : performance difference

标签 java atomic synchronized java.util.concurrent

在完成以下问题后 Can synchronized blocks be faster than Atomics? ,
我编写了一个简单的程序来比较 AtomicInteger 和同步块(synchronized block)(在其中递增 int)的性能差异。每次我运行这个程序时,它都会给我 ratio > 100。 我的笔记本电脑有 Intel Corei3,下一行显示 4。

    System.out.println(Runtime.getRuntime().availableProcessors())

当我使用

    THREAD_COUNT = 1;

比率最小。它在 100 左右变化。对于

    THREAD_COUNT = 10;  

比率在800左右。

问题 1:请问这是测试 AtomicInteger VS synchronized increment() 方法性能差异的正确方法吗?

问题 2:如果我增加 THREAD_COUNT,比率会增加,为什么?我认为这是因为更多的线程在 synchronized 语句中被阻塞并且需要更多的 CPU 任务。请评论。

package concurrent.atomic;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

public class Performance {

    private static final AtomicInteger atomicInt = new AtomicInteger(0);
    private static volatile int counter = 0;
    private static final Object LOCK = new Object();
    private static final int THREAD_COUNT = 10;

    public static void main(String[] args) {

        System.out.println(Runtime.getRuntime().availableProcessors()); 

        Runnable atomic = new Runnable() {
            @Override
            public void run() {
                while (!Thread.currentThread().isInterrupted()) {
                    int value = atomicInt.incrementAndGet();
                    //if (value % 1000 == 0)
                        //System.out.println("atomic value : "+value);
                }   
            }
        };
        //System.out.println("1");
        Runnable intCounter = new Runnable() {
            @Override
            public void run() {
                while (!Thread.currentThread().isInterrupted()) {
                    synchronized (LOCK) {
                        int value = ++counter;
                        //if (value % 1000 == 0)
                            //System.out.println("sync value "+value);
                    }
                }   
            }
        };

        final ExecutorService atomicExecutor = Executors.newCachedThreadPool();
        final ExecutorService primitiveExecutor = Executors.newCachedThreadPool();
        for (int i = 0; i < THREAD_COUNT ; ++i) {
            atomicExecutor.submit(atomic);
            primitiveExecutor.submit(intCounter);
        }

        while (true) {
            float ratio = (((float) (atomicInt.get() * 1.0) ) / counter) * 100;
            System.out.println("ratio : " + ratio);
        }
    }
}

最佳答案

Question 1 : Can you please tell me is this the correct way to test the performance difference of AtomicInteger VS synchronized increment() method?

您的测试代码存在一些细微的问题:

  • 如果您在 LOCK 上同步然后 counter不应该是 volatile .否则 synchronized代码正在为锁支付费用 volatile .
  • 如果counter不是 volatile那么您将需要在 LOCK 上同步当您读取 counter 的值时.
  • 你不应该在你的主线程中旋转。这将极大地影响您的性能测试。放一个Thread.sleep(100);在你的while至少循环。
  • 结果是 Thread.currentThread().isInterrupted()在我的 Mac 上相当昂贵。不知道为什么。将其切换为 while(true)改变了数字。

有了这个,您就可以更好地测试这两者,尽管这种孤立的测试除了您正在测试的内容外,并没有真正告诉我们任何其他信息。连续执行 100 万次中断与将 20 次中断混合到实际代码中是非常不同的。

Question 2 : If I increase THREAD_COUNT, ratio increases, why? I think it is because more threads get blocked at synchronized statement and requires more task for CPU. Please comment.

AtomicInteger.incrementAndGet()通过旋转工作,直到测试和设置成功。这与进行锁获取、递增和释放非常不同。在不了解精确的操作系统线程处理细节的情况下,很难解释这里发生的事情,我不确定这在所有情况下都是正确的。

在我的测试中,随着线程数量越来越多于我的处理器数量,该比率往往会出现相当大的波动。随着更多线程的添加,synchronize处理显然受到并发性增加的影响,尽管我不确定我还能从中得到什么。

关于java - AtomicInteger 与 Java 中的同步 int 变量 : performance difference,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15949192/

相关文章:

java - 同步方法 - 这是如何工作的?

java - OSGi 如何从远程机器安装 bundle ?

java - 一种从同一个类的构造函数中获取方法中的变量的方法?

java - 连接 sql server JAR 文件

java - 方法同步,但由于非序列化线程行为,代码产生随机结果

java - 线程转储被阻止并锁定

java - java中的文件读取

c++ - 如何确保成员是 4 字节对齐的?

c++ - 带有模板的奇怪解析行为 _Atomic

c++ - fetch_add with acq_rel 内存顺序