AtomicInteger在Java中同步int变量:性能差异

时间:2013-04-11 12:47:24

标签: java atomic synchronized java.util.concurrent

经过以下问题后 Can synchronized blocks be faster than Atomics?
我写了一个简单的程序来比较 AtomicInteger 和synchronized块(在其中增加int)的性能差异。每次我运行这个程序,它给我比率> 100。 我的笔记本电脑配备了英特尔酷睿2和以下系列打印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);
        }
    }
}

1 个答案:

答案 0 :(得分:0)

  

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

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

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

有了这个,那么你对这两个测试有了更好的测试,尽管这些孤立的测试并没有真正告诉我们你正在测试的东西。连续执行一百万次中断与20次中断混合成实际代码非常不同。

  

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

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

在我的测试中,随着线程数量越来越多,我的处理器数量越来越多,这个比率往往波动很大。随着更多线程的添加,synchronize处理明显受到并发性增加的影响,尽管我不知道还能从中得到什么。