java中SynchronizedList和Vector的區(qū)別詳解
前言
Vector是java.util包中的一個(gè)類(lèi)。 SynchronizedList是java.util.Collections中的一個(gè)靜態(tài)內(nèi)部類(lèi)。
在多線程的場(chǎng)景中可以直接使用Vector類(lèi),也可以使用Collections.synchronizedList(List list)方法來(lái)返回一個(gè)線程安全的List。
那么,到底SynchronizedList和Vector有沒(méi)有區(qū)別,為什么java api要提供這兩種線程安全的List的實(shí)現(xiàn)方式呢?
首先,我們知道Vector和Arraylist都是List的子類(lèi),他們底層的實(shí)現(xiàn)都是一樣的。所以這里比較如下兩個(gè)list1和list2的區(qū)別:
List<String> list = new ArrayList<String>(); List list2 = Collections.synchronizedList(list); Vector<String> list1 = new Vector<String>();
一、比較幾個(gè)重要的方法
1.1 add方法
Vector的實(shí)現(xiàn):
public void add(int index, E element) { insertElementAt(element, index); } public synchronized void insertElementAt(E obj, int index) { modCount++; if (index > elementCount) { throw new ArrayIndexOutOfBoundsException(index + " > " + elementCount); } ensureCapacityHelper(elementCount + 1); System.arraycopy(elementData, index, elementData, index + 1, elementCount - index); elementData[index] = obj; elementCount++; } private void ensureCapacityHelper(int minCapacity) { // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); }
synchronizedList的實(shí)現(xiàn):
public void add(int index, E element) { synchronized (mutex) { list.add(index, element); } }
這里,使用同步代碼塊的方式調(diào)用ArrayList的add()方法。ArrayList的add方法內(nèi)容如下:
public void add(int index, E element) { rangeCheckForAdd(index); ensureCapacityInternal(size + 1); // Increments modCount!! System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++; } private void rangeCheckForAdd(int index) { if (index > size || index < 0) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } private void ensureCapacityInternal(int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); }
從上面兩段代碼中發(fā)現(xiàn)有兩處不同:
- Vector使用同步方法實(shí)現(xiàn),synchronizedList使用同步代碼塊實(shí)現(xiàn)。
- 兩者的擴(kuò)充數(shù)組容量方式不一樣(兩者的add方法在擴(kuò)容方面的差別也就是ArrayList和Vector的差別。)
1.2 remove方法
synchronizedList的實(shí)現(xiàn):
public E remove(int index) { synchronized (mutex) {return list.remove(index);} }
ArrayList類(lèi)的remove方法內(nèi)容如下:
public E remove(int index) { rangeCheck(index); modCount++; E oldValue = elementData(index); int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // clear to let GC do its work return oldValue; }
Vector的實(shí)現(xiàn):
public synchronized E remove(int index) { modCount++; if (index >= elementCount) throw new ArrayIndexOutOfBoundsException(index); E oldValue = elementData(index); int numMoved = elementCount - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--elementCount] = null; // Let gc do its work return oldValue; }
從remove方法中我們發(fā)現(xiàn)除了一個(gè)使用同步方法,一個(gè)使用同步代碼塊之外幾乎無(wú)任何區(qū)別。
通過(guò)比較其他方法,我們發(fā)現(xiàn),SynchronizedList里面實(shí)現(xiàn)的方法幾乎都是使用同步代碼塊包上List的方法。如果該List是ArrayList,那么,SynchronizedList和Vector的一個(gè)比較明顯區(qū)別就是一個(gè)使用了同步代碼塊,一個(gè)使用了同步方法。
二、區(qū)別分析
數(shù)據(jù)增長(zhǎng)區(qū)別
從內(nèi)部實(shí)現(xiàn)機(jī)制來(lái)講ArrayList和Vector都是使用數(shù)組(Array)來(lái)控制集合中的對(duì)象。當(dāng)你向這兩種類(lèi)型中增加元素的時(shí)候,如果元素的數(shù)目超出了內(nèi)部數(shù)組目前的長(zhǎng)度它們都需要擴(kuò)展內(nèi)部數(shù)組的長(zhǎng)度,Vector缺省情況下自動(dòng)增長(zhǎng)原來(lái)一倍的數(shù)組長(zhǎng)度,ArrayList是原來(lái)的50%,所以最后你獲得的這個(gè)集合所占的空間總是比你實(shí)際需要的要大。所以如果你要在集合中保存大量的數(shù)據(jù)那么使用Vector有一些優(yōu)勢(shì),因?yàn)槟憧梢酝ㄟ^(guò)設(shè)置集合的初始化大小來(lái)避免不必要的資源開(kāi)銷(xiāo)。
同步代碼塊和同步方法的區(qū)別
- 同步代碼塊在鎖定的范圍上可能比同步方法要小,一般來(lái)說(shuō)鎖的范圍大小和性能是成反比的。
- 同步塊可以更加精確的控制鎖的作用域(鎖的作用域就是從鎖被獲取到其被釋放的時(shí)間),同步方法的鎖的作用域就是整個(gè)方法。
- 靜態(tài)代碼塊可以選擇對(duì)哪個(gè)對(duì)象加鎖,但是靜態(tài)方法只能給this對(duì)象加鎖。
因?yàn)镾ynchronizedList只是使用同步代碼塊包裹了ArrayList的方法,而ArrayList和Vector中同名方法的方法體內(nèi)容并無(wú)太大差異,所以在鎖定范圍和鎖的作用域上兩者并無(wú)卻別。 在鎖定的對(duì)象區(qū)別上,SynchronizedList的同步代碼塊鎖定的是mutex對(duì)象,Vector鎖定的是this對(duì)象。那么mutex對(duì)象又是什么呢? 其實(shí)SynchronizedList有一個(gè)構(gòu)造函數(shù)可以傳入一個(gè)Object,如果在調(diào)用的時(shí)候顯示的傳入一個(gè)對(duì)象,那么鎖定的就是用戶(hù)傳入的對(duì)象。如果沒(méi)有指定,那么鎖定的也是this對(duì)象。
所以,SynchronizedList和Vector的區(qū)別目前為止有兩點(diǎn):
- 如果使用add方法,那么他們的擴(kuò)容機(jī)制不一樣。
- SynchronizedList可以指定鎖定的對(duì)象。
但是,凡事都有但是。 SynchronizedList中實(shí)現(xiàn)的類(lèi)并沒(méi)有都使用synchronized同步代碼塊。其中有l(wèi)istIterator和listIterator(int index)并沒(méi)有做同步處理。但是Vector卻對(duì)該方法加了方法鎖。 所以說(shuō),在使用SynchronizedList進(jìn)行遍歷的時(shí)候要手動(dòng)加鎖。
但是,但是之后還有但是。
之前的比較都是基于我們將ArrayList轉(zhuǎn)成SynchronizedList。那么如果我們想把LinkedList變成線程安全的,或者說(shuō)我想要方便在中間插入和刪除的同步的鏈表,那么我可以將已有的LinkedList直接轉(zhuǎn)成 SynchronizedList,而不用改變他的底層數(shù)據(jù)結(jié)構(gòu)。而這一點(diǎn)是Vector無(wú)法做到的,因?yàn)樗牡讓咏Y(jié)構(gòu)就是使用數(shù)組實(shí)現(xiàn)的,這個(gè)是無(wú)法更改的。
所以,最后,SynchronizedList和Vector最主要的區(qū)別:
- SynchronizedList有很好的擴(kuò)展和兼容功能。他可以將所有的List的子類(lèi)轉(zhuǎn)成線程安全的類(lèi)。
- 使用SynchronizedList的時(shí)候,進(jìn)行遍歷時(shí)要手動(dòng)進(jìn)行同步處理。
- SynchronizedList可以指定鎖定的對(duì)象。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- 淺談Synchronized和Lock的區(qū)別
- Java線程安全解決方案(synchronized,ReentrantLock,Atomic)
- Java使用synchronized實(shí)現(xiàn)互斥鎖功能示例
- Java Synchronized鎖失敗案例及解決方案
- Java synchronized鎖升級(jí)jol過(guò)程詳解
- Java中synchronized正確使用方法解析
- JAVA面試題 簡(jiǎn)談你對(duì)synchronized關(guān)鍵字的理解
- Java對(duì)象級(jí)別與類(lèi)級(jí)別的同步鎖synchronized語(yǔ)法示例
相關(guān)文章
淺談maven 多環(huán)境打包發(fā)布的兩種方式
這篇文章主要介紹了淺談maven 多環(huán)境打包發(fā)布的兩種方式,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-08-08向Spring IOC 容器動(dòng)態(tài)注冊(cè)bean實(shí)現(xiàn)方式
這篇文章主要為大家介紹了向Spring IOC 容器動(dòng)態(tài)注冊(cè)bean實(shí)現(xiàn)方式詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07讀取Java文件到byte數(shù)組的三種方法(總結(jié))
下面小編就為大家?guī)?lái)一篇讀取Java文件到byte數(shù)組的三種方法(總結(jié))。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-08-08springmvc 中dao層和service層的區(qū)別說(shuō)明
這篇文章主要介紹了springmvc 中dao層和service層的區(qū)別說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08maven多個(gè)倉(cāng)庫(kù)查詢(xún)的優(yōu)先級(jí)順序案例講解
這篇文章主要介紹了maven多個(gè)倉(cāng)庫(kù)查詢(xún)的優(yōu)先級(jí)順序,考慮到我們常用的配置文件是conf/settings.xml和工程里面的pom.xml文件,我們針對(duì)這兩個(gè)文件的結(jié)合來(lái)分析倉(cāng)庫(kù)的使用順序,需要的朋友可以參考下2023-04-04Java AtomicInteger類(lèi)的使用方法詳解
這篇文章主要介紹了Java AtomicInteger類(lèi)的使用方法詳解,文中有具體實(shí)例代碼,具有一定參考價(jià)值,需要的朋友可以了解下。2017-10-10SpringBoot如何讀取配置文件中的數(shù)據(jù)到map和list
這篇文章主要介紹了SpringBoot如何讀取配置文件中的數(shù)據(jù)到map和list,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02SpringBoot+Vue前后端分離實(shí)現(xiàn)審核功能的示例
在實(shí)際開(kāi)發(fā)中,審核功能是一個(gè)非常常用的功能,本文就來(lái)介紹一下使用SpringBoot+Vue前后端分離實(shí)現(xiàn)審核功能的示例,具有一定的參考價(jià)值,感興趣的可以了解一下2024-02-02java List循環(huán)與Map循環(huán)的總結(jié)
這篇文章主要介紹了java List循環(huán)與Map循環(huán)的總結(jié)的相關(guān)資料,并附代碼實(shí)例,幫助大家學(xué)習(xí)理解,需要的朋友可以參考下2016-11-11