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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

java 集合读写同步_JAVA多线程学习十六 - 同步集合类的应用

發布時間:2023/12/6 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java 集合读写同步_JAVA多线程学习十六 - 同步集合类的应用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1.引言

在多線程的環境中,如果想要使用容器類,就需要注意所使用的容器類是否是線程安全的。在最早開始,人們一般都在使用同步容器(Vector,HashTable),其基本的原理,就是針對容器的每一個操作,都添加synchronized來進行同步,此種方式盡管簡單,但是其性能是非常地下的,所以現在已經不怎么使用了。人們普遍會使用并發的容器,在JDK1.5之后,針對基于散列的Map,提供了新的ConcurrentHashMap,針對迭代需求的list,提供了CopyOnWriteList.

2.ConcurrentHashMap

ConcurrentHashMap使用了一種分段鎖的策略,使得map可以被多個讀寫線程并行的訪問。基本可以認為是將map的key值范圍分為多個段,這樣多個線程訪問的時候,他們需要訪問的key值在不同的段,所以可以互相不干擾,

使用不同的鎖對象來進行并發操作。

ConcurrentHashMap在使用迭代器遍歷的時候,不會報ConcurrentModificationException,提供“弱一致性”。在遍歷迭代的時候,也會反應出在迭代器創建之后的數據修改。

應用場景

針對一般的有并發需求的map,都應該使用ConcurrentHashMap. 它的性能優于Hashtable和synchronizedMap。

缺點

不是強一致性

由于是采用的分段鎖策略,所以一些數據不能保證強一致性。比如針對容器的size方法,由于線程A只是獲得了自己的分段鎖,它不能保證其他線程對容器的修改,所以此時線程A可能使用size,會得到不穩定數據。這種情況下,是對同步性能的一些折衷。如果業務需求必須滿足強一致性,才會需要對整個Map進行鎖操作。并發容器的弱一致性的概念背景,是在高并發情況下,容器的size和isEmpty之類的方法,用處不大,所以可以忍受數據不一致性。

3.CopyOnWrite容器

在JDK1.5之后,java.util.concurrent引入了兩個CopyOnWrite容器,分別是CopyOnWriteArrayList, CopyOnWriteArraySet.

顧名思義,CopyOnWrite就是在write操作之前,對集合進行Copy,針對容器的任意改操作(add,set,remove之類),都是在容器的副本上進行的。并且在修改完之后,將原容器的引用指向修改后的副本。

如果線程A得到容器list1的iterator之后,線程B對容器list1加入了新的元素,由于線程A獲得list1的iterator時候在線程B對list1進行修改前,所以線程A是看不到線程B對list1進行的任何修改。

具體到源碼,看一下add操作

/**

* Appends the specified element to the end of this list.

*

* @param e element to be appended to this list

* @return {@code true} (as specified by {@link Collection#add})

*/

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();

}

}

可以發現,寫操作是會有個鎖lock.lock(),這保證了多線程寫操作之間的同步。之后使用Arrays.copyOf來進行數組拷貝,在修改完成后,setArray(newElements)將原來的數組引用指向新的數組。

應用場景

經常用在讀多寫少的場景,比如EventListener的添加,網站的category列表等偶爾修改,但是需要大量讀取的情景。

缺點

1.數據一致性的問題。

因為讀操作沒有用到并發控制,所以可能某個線程讀到的數據不是實時數據。

2.內存占用問題。

因為寫操作會進行數據拷貝,并且舊有的數據引用也可能被其他線程占有一段時間,這樣針對數據比較大的情況,可能會占用相當大的內存。并且由于每次寫操作都會占用額外的內存,最后進行的GC時間也可能相應的增加。

4.HashSet

HashSet內部是用的HashMap,只用了HashMap的key。

同步集合

傳統集合類在并發訪問時的問題說明:死鎖死循環

傳統方式下用Collections工具類提供的synchronizedCollection方法來獲得同步集合,分析該方法的實現源碼

Java5中提供了如下一些同步集合類:

通過看java.util.concurrent包下的介紹可以知道有哪些并發集合

ConcurrentHashMap

CopyOnWriteArrayList

CopyOnWriteArraySet

傳統方式下的Conllection在迭代結合時,不允許對集合進行修改。

根據AbstractList的checkForComodification方法的源碼,分析產生ConcurrentModificationException異常的原因。

public class User implements Cloneable{

private String name;

private int age;

public User(String name, int age) {

this.name = name;

this.age = age;

}

public boolean equals(Object obj) {

if(this == obj) {

return true;

}

if(!(obj instanceof User)) {

return false;

}

User user = (User)obj;

//if(this.name==user.name && this.age==user.age)

if(this.name.equals(user.name)

&& this.age==user.age) {

return true;

}

else {

return false;

}

}

public int hashCode() {

return name.hashCode() + age;

}

public String toString() {

return "{name:'" + name + "',age:" + age + "}";

}

public Object clone() {

Object object = null;

try {

object = super.clone();

} catch (CloneNotSupportedException e) {}

return object;

}

public void setAge(int age) {

this.age = age;

}

public String getName() {

return name;

}

}

總結

以上是生活随笔為你收集整理的java 集合读写同步_JAVA多线程学习十六 - 同步集合类的应用的全部內容,希望文章能夠幫你解決所遇到的問題。

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