synchronized與lock之間的性能比較

1.關於兩者的實現的比較

A).一般認爲synchronized關鍵字的實現是源自於像信號量之類的線程同步機制,涉及到線程運行狀態的切換,在高併發狀態下,CPU消耗過多的時間在線程的調度上,從而造成了性能的極大浪費。然而真的如此麼? 

線程的狀態主要有一下五種,分別是新建狀態,就緒狀態,運行狀態,阻塞狀態,消亡狀態等5種狀態


B).lock實現原理則是依賴於硬件,現代處理器都支持CAS指令,所謂CAS指令簡單的來說Compare And Set,CPU循環執行指令直到得到所期望的結果,換句話來說就是當變量真實值不等於當前線程調用時的值的時候(說明其他線程已經將這個值改變),就不會賦予變量新的值。這樣就保證了變量在多線程環境下的安全性。

然而,現實情況是當JDK版本高於1.6的時候,synchronized已經被做了CAS的優化:具體是這樣的,當執行到synchronized代碼塊時,先對對象頭的鎖標誌位用lock cmpxchg的方式設置成“鎖住“狀態,釋放鎖時,在用lock cmpxchg的方式修改對象頭的鎖標誌位爲”釋放“狀態,寫操作都立刻寫回主內存。JVM會進一步對synchronized時CAS失敗的那些線程進行阻塞操作(調用操作系統的信號量)(此段來摘自別處)。也就是先CAS操作,不行的話繼而阻塞線程。

除此之外,系統環境,CPU架構,虛擬機環境都會影響兩者的性能關係。

舉例如下

1).X86_64 cpu i7 4910mq @4.0ghz ,Windows10 64bit,JDK1.8 hotspot 64bit虛擬機環境

測試代碼

測試對某Map對象高併發下的讀寫線程安全測試 
測試對比有synchronized,ReadWriteLock,ConcurrentHashMap,

public class MapTest {

     private Map<Integer,String> map = new ConcurrentHashMap<>();

     private long starttime;

     private AtomicInteger count = new AtomicInteger(t_count);

     private final static int t_count = 5000;

     private final static int rw_count = 10000;

        Runnable readrun = new Runnable() {
            @Override
            public void run() {
                int i = rw_count;
                while (i > 0){
                    map.get(i);
                    i--;
                }
                System.out.println("read-mapsize="+map.size());
                if(count.decrementAndGet() == 0)
                    System.out.println("time="+ (System.currentTimeMillis() - starttime +"ms"));
            }
        };

        Runnable writerun = new Runnable() {
            @Override
            public void run() {
                int i = rw_count;
                while (i > 0){
                    map.put(i,i+"");
                    i--;
                }
                System.out.println("write-mapsize="+map.size());
                if(count.decrementAndGet() == 0)
                    System.out.println("time="+ (System.currentTimeMillis() - starttime + "ms"));
            }
        };

        public void run(){
            starttime = System.currentTimeMillis();
            for(int i = 0;i < t_count/2;i ++){
                new Thread(writerun).start();
                new Thread(readrun).start();
            }
        }
}

HashMap 用synchronized重寫

public class SyncHashMap extends HashMap{

    @Override
    public Object get(Object key) {
        // TODO Auto-generated method stub
        synchronized (this) {
            return super.get(key);
        }
    }

    @Override
    public synchronized Object put(Object key, Object value) {
        // TODO Auto-generated method stub
        synchronized (this) {
            return super.put(key, value);
        }

    }

}

用讀寫鎖實現的Map代理類,有些粗糙,沒加try finally

public class SyncMapProxy<K,V> implements Map<K,V>{

    private Map<K,V> origin;
    private ReadWriteLock lock;

    public SyncMapProxy(Map<K, V> origin) {
        this.origin = origin;
        lock = new ReentrantReadWriteLock();
    }

    public static  <K,V> SyncMapProxy<K,V> SyncMap(Map<K,V> map){
        return new SyncMapProxy<K,V>(map);
    }

    @Override
    public void clear() {
        lock.writeLock().lock();
        origin.clear();
        lock.writeLock().unlock();
    }

    @Override
    public boolean containsKey(Object key) {
        lock.readLock().lock();
        boolean res = origin.containsKey(key);
        lock.readLock().unlock();
        return res;
    }

    @Override
    public boolean containsValue(Object value) {
        lock.readLock().lock();
        boolean res = origin.containsKey(value);
        lock.readLock().unlock();
        return res;
    }

    @Override
    public Set<Entry<K, V>> entrySet() {
        lock.readLock().lock();
        Set<Entry<K, V>> res = origin.entrySet();
        lock.readLock().unlock();
        return res;
    }

    @Override
    public V get(Object key) {
        lock.readLock().lock();
        V res = origin.get(key);
        lock.readLock().unlock();
        return res;
    }

    @Override
    public boolean isEmpty() {
        return origin.isEmpty();
    }

    @Override
    public Set<K> keySet() {
        lock.readLock().lock();
        Set<K> res = origin.keySet();
        lock.readLock().unlock();
        return res;
    }

    @Override
    public V put(K key, V value) {
        lock.writeLock().lock();
        V v = origin.put(key, value);
        lock.writeLock().unlock();
        return v;
    }

    @Override
    public void putAll(Map<? extends K, ? extends V> map) {
        lock.writeLock().lock();
        origin.putAll(map);
        lock.writeLock().unlock();
    }

    @Override
    public V remove(Object key) {
        lock.writeLock().lock();
        V v = origin.remove(key);
        lock.writeLock().unlock();
        return v;
    }

    @Override
    public int size() {
        return origin.size();
    }

    @Override
    public Collection<V> values() {
        lock.readLock().lock();
        Collection<V> res = origin.values();
        lock.readLock().unlock();
        return res;
    }
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章