【问题标题】:AtomicInteger Vs synchronized int variable in Java : performance differenceJava 中的 AtomicInteger 与同步的 int 变量:性能差异
【发布时间】:2013-04-03 16:08:07
【问题描述】:

在完成以下问题后 Can synchronized blocks be faster than Atomics?,
我写了一个简单的程序来比较 AtomicInteger 和 synchronized 块(在其中递增 int)的性能差异。每次我运行这个程序时,它给我的比率 > 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,比例增加,为什么?我认为这是因为更多的线程在同步语句中被阻塞并且需要更多的 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);
        }
    }
}

【问题讨论】:

  • kennethxu.blogspot.in/2009/05/… 这样做。发现这个谷歌搜索。试试这个。
  • 你这里有个bug,你需要将counter声明为volatile。否则不保证主线程读取到最新的值。
  • 是的..我需要更改我的代码。
  • 您的分析很有道理。您可以不时将计数器重置为 0 以避免溢出,更重要的是在 JIT 之前和之后进行计算。

标签: java atomic synchronized java.util.concurrent


【解决方案1】:

问题 1:请问这是测试 AtomicInteger 与同步增量()方法性能差异的正确方法吗?

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

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

有了这个,你就可以更好地测试这两者了,尽管这种孤立的测试除了你正在测试的东西之外并没有真正告诉我们任何东西。连续执行一百万个中断与将 20 个中断混合到实际代码中是非常不同的。

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-31
    • 1970-01-01
    相关资源
    最近更新 更多