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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

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

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

1.引言

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

2.ConcurrentHashMap

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

使用不同的鎖對(duì)象來(lái)進(jìn)行并發(fā)操作。

ConcurrentHashMap在使用迭代器遍歷的時(shí)候,不會(huì)報(bào)ConcurrentModificationException,提供“弱一致性”。在遍歷迭代的時(shí)候,也會(huì)反應(yīng)出在迭代器創(chuàng)建之后的數(shù)據(jù)修改。

應(yīng)用場(chǎng)景

針對(duì)一般的有并發(fā)需求的map,都應(yīng)該使用ConcurrentHashMap. 它的性能優(yōu)于Hashtable和synchronizedMap。

缺點(diǎn)

不是強(qiáng)一致性

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

3.CopyOnWrite容器

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

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

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

具體到源碼,看一下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();

}

}

可以發(fā)現(xiàn),寫(xiě)操作是會(huì)有個(gè)鎖lock.lock(),這保證了多線程寫(xiě)操作之間的同步。之后使用Arrays.copyOf來(lái)進(jìn)行數(shù)組拷貝,在修改完成后,setArray(newElements)將原來(lái)的數(shù)組引用指向新的數(shù)組。

應(yīng)用場(chǎng)景

經(jīng)常用在讀多寫(xiě)少的場(chǎng)景,比如EventListener的添加,網(wǎng)站的category列表等偶爾修改,但是需要大量讀取的情景。

缺點(diǎn)

1.數(shù)據(jù)一致性的問(wèn)題。

因?yàn)樽x操作沒(méi)有用到并發(fā)控制,所以可能某個(gè)線程讀到的數(shù)據(jù)不是實(shí)時(shí)數(shù)據(jù)。

2.內(nèi)存占用問(wèn)題。

因?yàn)閷?xiě)操作會(huì)進(jìn)行數(shù)據(jù)拷貝,并且舊有的數(shù)據(jù)引用也可能被其他線程占有一段時(shí)間,這樣針對(duì)數(shù)據(jù)比較大的情況,可能會(huì)占用相當(dāng)大的內(nèi)存。并且由于每次寫(xiě)操作都會(huì)占用額外的內(nèi)存,最后進(jìn)行的GC時(shí)間也可能相應(yīng)的增加。

4.HashSet

HashSet內(nèi)部是用的HashMap,只用了HashMap的key。

同步集合

傳統(tǒng)集合類(lèi)在并發(fā)訪問(wèn)時(shí)的問(wèn)題說(shuō)明:死鎖死循環(huán)

傳統(tǒng)方式下用Collections工具類(lèi)提供的synchronizedCollection方法來(lái)獲得同步集合,分析該方法的實(shí)現(xiàn)源碼

Java5中提供了如下一些同步集合類(lèi):

通過(guò)看java.util.concurrent包下的介紹可以知道有哪些并發(fā)集合

ConcurrentHashMap

CopyOnWriteArrayList

CopyOnWriteArraySet

傳統(tǒng)方式下的Conllection在迭代結(jié)合時(shí),不允許對(duì)集合進(jìn)行修改。

根據(jù)AbstractList的checkForComodification方法的源碼,分析產(chǎn)生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;

}

}

總結(jié)

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

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。