簡體   English   中英

寫時復制與直接鎖定/寫入時同步方法有何不同?

[英]How Copy-On-Write is different from a direct lock / synchronized on write method?

寫時復制被認為是並發方案中的良好實踐之一。 但是,我不清楚它與寫方法上的簡單鎖/同步有何不同。 有人可以幫忙解釋一下嗎?

寫時復制:

    public V put(K key, V value) {
        synchronized (this) {
            Map<K, V> newMap = new HashMap<K, V>(internalMap);
            V val = newMap.put(key, value);
            internalMap = newMap;
            return val;
        }
    }

直接鎖定/同步:

    public V put(K key, V value) {
        synchronized (this) {
            internalMap.put(key, value);
        }
    }

對於寫線程,在​​上面的兩個示例中,它們相互排斥,相同。

對於讀取線程,在“寫時復制”中,運行“ internalMap = newMap”后的讀取操作將獲取更新后的值。 並且在直接鎖定中,運行“ internalMap.put(key,value)”后的讀取動作將獲得更新后的值。

那么,為什么我們要推廣寫時復制? 為什么我們在寫時必須“復制”?

此示例的一個好處是,您可以獲得寫時復制的快照語義:對internalMap每個引用都是不可變的,一旦獲得,就不會再更改。 當您有許多並發的讀取操作遍歷internalMap且僅偶爾進行更新時,這可能會很有用。

使用鎖定和寫時復制都可以(實際上)實現相同的功能。 他們中的任何一個都沒有天生比另一個更好。

通常,在有很多讀取但很少寫入的情況下,寫時復制性能會更好。 這是因為平均而言,讀取比使用鎖便宜,而由於復制,寫入更昂貴。 當您進行大量寫操作時,通常最好使用鎖。

為什么寫操作更昂貴的原因很明顯(您必須在每次寫操作時都復制整個映射,,)。 讀取便宜的原因如下:

volatile Map<K, V> internalMap = new HashMap<>();

讀取internalMap不需要獲取鎖(有關更多詳細信息,請參見Java中volatile和sync之間的區別 )。 一旦線程獲得了對internalMap的引用,它們就可以繼續處理該副本(例如,遍歷條目),而無需與其他線程進行協調,因為可以保證它不會被突變。 盡可能多的線程可以處理單個映射副本(快照)。

為了進行類比解釋,請想象一個作者正在起草一篇文章,並且有一些人作為事實檢查者。 使用鎖時,其中只有一個可以處理草稿。 使用寫時復制,作者將一個不變的快照(副本)發布到某個地方,事實檢查人員可以抓取並完成他們的工作-在工作時,他們可以根據需要讀取快照(而不是每次都中斷作者)忘記了文章的某些部分等)。

多年來,Java的鎖已得到改進,因此差異很小,但是在極端情況下,不必獲取鎖/不必在線程之間進行協調會導致更高的吞吐量等。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM