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

(2011-10-31) synchronized与lock,哪个效率更高

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

Java在一开始就提供了synchronized关键字,用于多线程之间的同步。它使用简便,不会出现拿锁之后不归还的情况,可以避免一些编程错误。

而jdk5时提供的concurrent包里,有一个Lock接口以及它的实现类:ReentrantLock。这个类提供了更灵活的控制以及更强大的功能。

如果单从性能方面考虑,两个哪个更高效呢?

首先是单线程的加锁情况,见以下代码:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class SynLockTest {

public static void main(String[] args) {      
    long value = 0;       
    int MAX = 10000000;       
    Lock lock = new ReentrantLock();       
    long start = System.nanoTime();       
    for (int i = 0; i < MAX; i++) {       
        synchronized (new Object()) {       
            value = value + 1;       
        }       
    }       
    long end = System.nanoTime();       
    System.out.println("synchronized cost: " + (end - start)/1000000 + "ms"); 

    start = System.nanoTime();      
    for (int i = 0; i < MAX; i++) {       
        lock.lock();       
        try {       
            value = value + 1;       
        } finally {       
            lock.unlock();       
        }       
    }       
    end = System.nanoTime();       
    System.out.println("lock cost: " + (end - start) + "ns");       
}       

}

结果如下:

synchronized cost: 405ms
lock cost: 479ms

可见Lock的运行时间比synchronized略大。可以推测java编译器为synchronized做了特别优化。

再考虑多线程情况:

public class SynLockTest {

static class SynRunner implements Runnable {      
    private long v = 0; 

    @Override      
    public synchronized void run() {       
        v = v + 1;       
    }       
} 

static class LockRunner implements Runnable {      
    private ReentrantLock lock = new ReentrantLock();       
    private long v = 0; 

    @Override      
    public void run() {       
        lock.lock();       
        try {       
            v = v + 1;       
        } finally {       
            lock.unlock();       
        }       
    } 

} 

static class Tester {      
    private AtomicLong runCount = new AtomicLong(0);       
    private AtomicLong start = new AtomicLong();       
    private AtomicLong end = new AtomicLong(); 

    public Tester(final Runnable runner, int threadCount) {      
        final ExecutorService pool = Executors.newFixedThreadPool(threadCount);       
        Runnable task = new Runnable() {       
            @Override       
            public void run() {       
                while (true) {       
                    runner.run();      
                    long count = runCount.incrementAndGet();       
                    if (count == 1) {       
                        start.set(System.nanoTime());       
                    } else if (count >= 10000000) {       
                        if (count == 10000000) {       
                            end.set(System.nanoTime());       
                            System.out.println(runner.getClass().getSimpleName() + ", cost: "       
                                    + (end.longValue() - start.longValue())/1000000 + "ms");                            }       
                            pool.shutdown();       
                        return;       
                    }       
                }       
            }       
        };       
        for (int i = 0; i < threadCount; i++) {       
            pool.submit(task);       
        }       
    }       
} 

public static void main(String[] args) {      
    new Tester(new SynRunner(), 1);       
    new Tester(new LockRunner(), 1);       
} 

}

现在测试不同线程下的表现(时间单位ms):

1 10 50 100 500 1000 5000
synchronized 542 4894 4667 4700 5151 5156 5178
lock 838 1211 821 847 851 1211 1241

可以看到,在多线程环境并存在大量竞争的情况下,synchronized的用时迅速上升,而lock却依然保存不变或增加很少。

comments powered by Disqus