synchronized與lock,哪個效率更高


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卻依然保存不變或增加很少。

 

Lock是用CAS來實現的
JDK 1.6以上synchronized也改用CAS來實現了,所以兩者性能差不多
Lock提供的功能豐富點,synchronized的使用簡單點


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM