Freewind @ Thoughtworks scala java javascript dart 工具 编程实践 月结 math python english [comments admin] [feed]

(2011-10-22) 原子操作与synchronized在多线程环境下的性能差别

广告: 云梯:翻墙vpn (省10元) 土行孙:科研用户翻墙http proxy (有优惠)

从另一篇两者在单线程环境下的测试可以看出,就算没有竞争,synchronized也比原子操作慢。地址如下:http://freewind.me/blog/20111022/457.html

这里测试多线程环境下的影响。重构了代码,如下:

public class IncTestN {

    public static int MAX_COUNT = 50000000;
    public static int THREADS = 1;

    interface Incer {
        long inc();
    }

    static class AtomIncer implements Incer {
        private AtomicLong atom = new AtomicLong();

        @Override
        public long inc() {
            return atom.incrementAndGet();
        }
    }

    static class SynIncer implements Incer {
        private long syn = 0;

        @Override
        public synchronized long inc() {
            syn += 1;
            return syn;
        }
    }

    static class Tester {
        ExecutorService pool = Executors.newFixedThreadPool(THREADS);
        Incer incer;
        final AtomicLong start = new AtomicLong(0);
        final AtomicLong end = new AtomicLong(0);

        public Tester(Incer incer) {
            this.incer = incer;
        }

        public long test() throws InterruptedException {
            Callable<Void> task = new Callable<Void>() {
                @Override
                public Void call() throws Exception {
                    while (true) {
                        long v = incer.inc();
                        if (v == 1) {
                            start.set(System.nanoTime());
                        } else if (v == MAX_COUNT) {
                            end.set(System.nanoTime());
                            break;
                        } else if (v > MAX_COUNT) {
                            break;
                        }
                    }
                    return null;
                }
            };
            List<Callable<Void>> list = new ArrayList<Callable<Void>>();
            for (int i = 0; i < THREADS; i++) {
                list.add(task);
            }
            pool.invokeAll(list);
            long cost = (end.longValue() - start.longValue()) / 1000000;
            pool.shutdownNow();
            return cost;
        }
    }

    public static void main(String[] args) throws Exception {
        long atomCost = new Tester(new AtomIncer()).test();
        System.out.println("Atom cost: " + atomCost + "ms");

        long synCost = new Tester(new SynIncer()).test();
        System.out.println("Synchronized cost: " + synCost + "ms");
    }
}

通过修改THREADS的值,在我的电脑上可以得到以下数据:

线程数 1 2 5 10 20 50
atom 1413ms 5066ms 5226ms 5283ms 5328ms 5248ms
synchronized 1913ms 24560ms 25895ms 25507ms 25172ms 25459ms

可见,当变为多线程后,两者的用时都变多了,而synchronized受到的影响要大得多。

但从表中发现,2个线程与50个线程用时差不多。这又应该如何解释呢?

我想可能是因为我们的逻辑代码比较简单,在一个线程运行的时间内,就足以运行大量的循环,所以线程的切换与竞争,没并有想像中那么频繁。但这也已经让性能受到了很大的影响。

所以在代码中,还是要尽量避免或减少synchronized的使用。这种性能问题很难测试出来。

comments powered by Disqus