Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 写时复制与直接锁定/写时同步方法有何不同?_Java_Multithreading_Concurrency - Fatal编程技术网

Java 写时复制与直接锁定/写时同步方法有何不同?

Java 写时复制与直接锁定/写时同步方法有何不同?,java,multithreading,concurrency,Java,Multithreading,Concurrency,写时复制被认为是并发场景中的良好实践之一。但是,我不清楚它与写方法上的简单锁定/同步有什么不同。有人能解释一下吗 书面复制: public V put(K key, V value) { synchronized (this) { Map<K, V> newMap = new HashMap<K, V>(internalMap); V val = newMap.put(key, value);

写时复制被认为是并发场景中的良好实践之一。但是,我不清楚它与写方法上的简单锁定/同步有什么不同。有人能解释一下吗

书面复制:

    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;
        }
    }
对于写线程,在上述两个示例中,它们是相互排除的,相同

对于读线程,在写时复制中,运行“internalMap=newMap”后的读操作将获得更新的值。在直接锁中,运行“internalMap.put(key,value)”之后的读取操作将获得更新的值,大致相同


那么,我们为什么要推广书面复制呢?为什么我们在编写时必须“复制”?

本例中的一个好处是,您可以获得写时复制案例的快照语义:对
internalMap
的每个引用都是不可变的,一旦获得,就不会再更改。当您有许多并发读取操作遍历
internalMap
,并且只有偶尔的更新时,这会非常有用

使用锁和写时复制(实际上)实现了相同的功能。它们中没有一个天生比另一个更好

一般来说,当有大量读取,但很少写入时,即写即复制性能更好。这是因为平均而言,读取比使用锁时更便宜,而写入由于复制而更昂贵。当您有大量写入时,通常最好使用锁

为什么写东西更贵可能是显而易见的(你必须在每次写东西时复制整个地图,duh)。价格便宜的原因如下:

volatile Map<K, V> internalMap = new HashMap<>();
volatile Map internalMap=new HashMap();
读取internalMap不需要获取锁(有关更多详细信息,请参阅)。一旦线程获得了对
internalMap
的引用,它们就可以继续处理该副本(例如,遍历条目),而无需与其他线程协调,因为可以保证它不会发生变异。根据需要,可以使用多个线程创建映射的单个副本(快照)

通过类比来解释,假设一位作者正在起草一篇文章,他们有几个人作为他们的事实核查员。有了锁,他们中只有一个人可以在草稿上工作。通过写时复制,作者将一个不可变的快照(副本)发布到某个地方,事实核查人员可以抓取该快照并执行其工作-在他们执行工作时,他们可以根据需要读取快照(而不是每次忘记文章的某个部分时都打断作者)


Java的锁多年来有所改进,因此差异很小,但在极端情况下,不必获取锁/不必在线程之间协调可能会导致更高的吞吐量等。

这个示例是从哪里获得的?还是你自己想出来的?至少有一个好处是可以不锁定地进行迭代。
volatile Map<K, V> internalMap = new HashMap<>();