【多線程】六、鎖與同步

相關文章:
【多線程】一、線程狀態切換
【多線程】二、線程優先級&守護線程
【多線程】三、線程訪問變量
【多線程】四、線程異常抓捕
【多線程】五、線程池
【多線程】六、鎖與同步
【多線程】七、阻塞隊列
【多線程】八、異步計算結果獲取
【多線程】九、Android異步任務

鎖定的代碼塊在多線程訪問的時候以串行的方式執行,可以保證可見性有序性原子性

概念 含義
可見性 每個線程有自己的內存緩存,其他線程緩存在本線程中不可見
原子性 對於非單一的指令,要麼都執行,要麼都不執行
有序性 編譯優化對指令進行重排序,只保證重排序的結果和沒排序的結果一致(happens-before規則)

Lock和Condition

ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();

// 鎖測試,代替lock.lock()發生死鎖時可超時終止
// lockInterruptibly()無休止嘗試直到被interrupt();
if (lock.tryLock(3000, TimeUnit.MILLISECONDS)) { 
    try {
        if (不滿足業務條件) {
            condition.await();
            // 等待被喚醒: condition.signalAll();
        }
        // 獲取鎖成功, do ...
    } finally {
        lock.unlock();
    }
} else { //
    // 獲取鎖超時, do ...
}

同步修飾
synchornized方法默認用當前對象class對象作爲鎖;
synchornized代碼塊需要顯示加對象鎖;
對象鎖只有一個默認條件(Object#wait(),Object#notifyAll());

鎖相關

  • 有鎖編程:從悲觀角度看待,認爲併發操作一定導致數據修改,必須加鎖保證數據的正確;

  • 無鎖編程:從樂觀角度看待,認爲併發操作不一定導致數據修改,通常使用CAS算法實現;如java.concurrent.atomic.*, 但CAS可能會導致ABA問題,可用AtomicMarkableReference<T>AtomicStampedReference<T>避免

  • 分段設計: 一種鎖的設計思想;如ConcurrentHashMap中以每個Hash桶鏈表作爲鎖,put操作時對某個段加鎖,這樣實現了並行插入;

  • 自旋設計: 線程在獲取鎖的時候不立即阻塞而是通過忙循環嘗試,減少線程上下文切換的消耗。這一行爲會消耗CPU,基於JVM的線程調度可讓出忙循環時間片不會形成死鎖;

公平性 說明
非公平 線程獲取鎖的順序不一定是申請順序,而爲保證最大吞吐量由系統自由調度;
可能會導致優先級反轉或飢餓現象
公平 線程獲取鎖的順序和申請的順序一致;
ReentrantLock底層通過AbstractQueueSynchronizer(AQS)實現調度,可指定爲公平策略;
synchronized修飾無法構造公平鎖;
可重入性 說明
可重入(遞歸鎖) 外層方法獲取鎖以後進入內層方法可自動取得鎖;
ReentrantLocksynchronized都是可重入鎖;
不可重入 同一線程,內層方法不能取得外層方法的鎖,阻塞形成死鎖
共享性 說明
獨享(互斥鎖) 鎖在同一時刻只能被一個線程獲取;
ReentrantLocksynchronized都是獨享鎖;
共享(讀寫鎖) 鎖在同一時刻可以被多個線程獲取;
ReadWriteLock讀鎖通過AQS實現讀取與讀取共享;
鎖膨脹 說明
偏向鎖 如果一個鎖(synchronized)一直被同一個線程訪問,那麼該線程可以自動獲取偏向它鎖而無需申請;
輕量級鎖 若一個偏向鎖有了另一線程在申請,此時該鎖膨脹爲輕量級鎖,非偏向線程通過自旋獲取這個鎖
重量級鎖 若自旋一段時間還沒取得鎖,則線程休眠,鎖膨脹爲重量級鎖;重量級鎖在申請時會阻塞線程;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章