日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java多线程基本概述(二十六)——免锁容器

發布時間:2025/1/21 编程问答 96 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java多线程基本概述(二十六)——免锁容器 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

容器是所有編程中的基礎工具,這其中也包括并發編程。出于這個原因,像Vector和Hashtable這類早期容器具有許多synchronized方法,當他們用于非多線程的應用程序中時,便會導致不可接受的開銷。在Java1.2中,新的容器類庫是不同步的,并且Collections類提供了各種static的同步的裝飾方法,從而來同步不同類型的容器。盡管這是一種改進,因為它使你可以選擇在你的容器中是否要使用同步,但是這種開銷仍舊是基于synchronized加鎖機制的。Java SE5特別添加了新容器,通過使用更靈巧的技術消除加鎖,從而提高線程的安全的性能。

這些免鎖容器背后的通用策略是:對容器的修改可以與讀取操作同時發生,只要讀取者只能看到完成修改后的結果即可。修改是在容器數據結構的某一部分的一個單獨的副本(有時是整個數據結構的副本)上執行的,并且這個副本在修改過程中是不可視的。只有當修改完成時,被修改的結構才會自動地與主數據結構進行交換,之后讀取者就可以看到這個修改了。

在CopyOnWriteArrayList中,寫入將導致創建整個底層數組的副本,而源數組將保留在原地,使得復制的數組在被修改時,讀取操作可以安全的執行。當修改完成時,一個原子性操作將把新的數組換入,使得新的讀取操作可以看到這個新的修改。CopyOnWriteArrayList的好處之一是當多個迭代器同時遍歷和修改這個列表時,不會拋出ConcurrentModificationException,因此你不必編寫特殊的代碼去防范這種異常,就像你以前必須作的那樣。

迭代器上進行的元素更改操作(remove、set?和?add)不受支持。這些方法將拋出?UnsupportedOperationException。

CopyOnWriteArraySet將使用CopyOnWriteArrayList來實現其免鎖行為。

ConcurrentHashMap和ConcurrentLinkedQueue使用了類似的技術,允許并發的讀取和寫入,但是容器中只有部分內容而不是整個容器可以被復制和修改。然而,任何修改在完成之前,讀取者仍舊不能看到它們。ConcurrentHashMap不會拋出ConcurrentModificationException異常。

??CopyOnWriteArrayList適合用在“讀多,寫少”的“并發”應用中,換句話說,它適合使用在讀操作遠遠大于寫操作的場景里,比如緩存。它不存在“擴容”的概念,每次寫操作(add or remove)都要copy一個副本,在副本的基礎上修改后改變array引用,所以稱為“CopyOnWrite”,因此在寫操作是加鎖,并且對整個list的copy操作時相當耗時的,過多的寫操作不推薦使用該存儲結構。

?

一個ConcurrentHashMap由多個segment組成,每一個segment都包含了一個HashEntry數組的hashtable, 每一個segment包含了對自己的hashtable的操作,比如get,put,replace等操作,這些操作發生的時候,對自己的hashtable進行鎖定。由于每一個segment寫操作只鎖定自己的hashtable,所以可能存在多個線程同時寫的情況,性能無疑好于只有一個hashtable鎖定的情況。

?

?

源碼分析 在ConcurrentHashMap的remove,put操作還是比較簡單的,都是將remove或者put操作交給key所對應的segment去做的,所以當幾個操作不在同一個segment的時候就可以并發的進行。

public V remove(Object key) {int hash = hash(key.hashCode());return segmentFor(hash).remove(key, hash, null);}

而segment中的remove操作除了加鎖之外和HashMap中的remove操作基本無異

V remove(Object key, int hash, Object value) {lock();try {int c = count - 1;HashEntry<K,V>[] tab = table;int index = hash & (tab.length - 1);HashEntry<K,V> first = tab[index];HashEntry<K,V> e = first;while (e != null && (e.hash != hash || !key.equals(e.key)))e = e.next;V oldValue = null;if (e != null) {V v = e.value;if (value == null || value.equals(v)) {oldValue = v;// All entries following removed node can stay// in list, but all preceding ones need to be// cloned.++modCount;HashEntry<K,V> newFirst = e.next;for (HashEntry<K,V> p = first; p != e; p = p.next)newFirst = new HashEntry<K,V>(p.key, p.hash,newFirst, p.value);tab[index] = newFirst;count = c; // write-volatile }}return oldValue;} finally {unlock();}}

?

package tij;import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;/*** Created by huaox on 2017/4/21.**/ public class CopyOnWriteArrayListDemo {private static class ReadTask implements Runnable {List<String> list;ReadTask(List<String> list) {this.list = list;}public void run() {for (String str : list) {System.out.println(str);}}}private static class WriteTask implements Runnable {List<String> list;int index;WriteTask(List<String> list, int index) {this.list = list;this.index = index;}public void run() {list.remove(index);list.add(index, "write_" + index);}}public void run() {final int NUM = 5;List<String> list = new ArrayList<String>();for (int i = 0; i < NUM; i++) {list.add("main_" + i);}ExecutorService executorService = Executors.newFixedThreadPool(NUM);for (int i = 0; i < NUM; i++) {executorService.execute(new ReadTask(list));executorService.execute(new WriteTask(list, i));}executorService.shutdown();}public static void main(String[] args) {new CopyOnWriteArrayListDemo().run();} }

輸出結果:

Exception in thread "pool-1-thread-3" java.util.ConcurrentModificationException main_0 main_1at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901) main_2 main_3at java.util.ArrayList$Itr.next(ArrayList.java:851) main_4 main_0 main_1 write_2 main_3 main_4 main_0 main_1 write_2 write_3 main_4 main_0 write_0 write_1at tij.CopyOnWriteArrayListDemo$ReadTask.run(CopyOnWriteArrayListDemo.java:22) write_2 write_3at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) write_4at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)at java.lang.Thread.run(Thread.java:745)Process finished with exit code 0

免鎖容器的源碼為賦值底層數組,然后賦新值,改引用

public boolean add(E e) {final ReentrantLock lock = this.lock;lock.lock();try {Object[] elements = getArray();int len = elements.length;Object[] newElements = Arrays.copyOf(elements, len + 1);newElements[len] = e;setArray(newElements);return true;} finally {lock.unlock();}}

修改為CopyOnWriteArrayList后

public void run() {final int NUM = 5;List<String> list = new CopyOnWriteArrayList<>();for (int i = 0; i < NUM; i++) {list.add("main_" + i);}ExecutorService executorService = Executors.newFixedThreadPool(NUM);for (int i = 0; i < NUM; i++) {executorService.execute(new ReadTask(list));executorService.execute(new WriteTask(list, i));}executorService.shutdown();}

輸出結果:

main_0 main_1 main_2 main_3 main_4 main_0 main_1 write_2 main_3 main_4 write_0 main_1 write_2 write_3 main_4 write_0 main_1 write_2 write_3 write_4 write_0 write_1 write_2 write_3 write_4Process finished with exit code 0

?

轉載于:https://www.cnblogs.com/soar-hu/p/6742694.html

總結

以上是生活随笔為你收集整理的java多线程基本概述(二十六)——免锁容器的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。