基于java構(gòu)造方法Vevtor添加元素源碼分析
(注意:本文基于JDK1.8)
前言
算上迭代器的add()方法,Vector中一共有7個添加元素的方法,5個添加單個元素的方法,2個添加多個元素的方法,接下來就一起分析它們的實現(xiàn)……Vector是一個線程安全的容器類,它的添加功能是如何做到線程安全的呢?
add(E)方法分析
public synchronized boolean add(E e) { modCount++; ensureCapacityHelper(elementCount + 1); elementData[elementCount++] = e; return true; }
用于添加1個元素的方法,由synchronized修飾,只有獲得對象鎖的線程才可以執(zhí)行該方法,其它未獲得對象鎖的線程會blocked在方法的入口處,等待已經(jīng)持有對象鎖的線程釋放對象鎖,傳入的參數(shù)為即將要添加的元素對象,類型為指定的類型參數(shù)E
1、首先修改modCount值
Vecotor的父類AbstractList中,定義了實例變量modCount,這意味著每個Vector對象也持有一個modCount,這里將其+1,表示當前Vector對象持有的元素發(fā)生變化,這個modCount值是用于防止用戶在多線程下使用容器類而設(shè)計的,常被稱為fail-fast機制,可Vector本身是線程安全的容器類,為何這里還在使用modCount做++呢?費解……
2、然后檢查底層數(shù)組容量能否再添加一個新的元素
通過調(diào)用ensureCapacityHelper()方法檢查,傳入?yún)?shù)是實際元素總數(shù)+1后的一個值,用于確認當前數(shù)組的容量是否需要擴充容量,如果數(shù)組的容量無法再添加一個新的元素,則在此方法中會對當前Vector對象持有的數(shù)組對象進行容量擴充(擴容的方法,將在單獨的文章中分析,這里只需知道,容量不夠,先擴容)
3、將元素賦值到數(shù)組對象中某個下標處,并增加表示元素總數(shù)的實例變量
先使用Vector對象持有的elmentCount作為數(shù)組下標,將新增加的元素賦值給elementData數(shù)組中對應(yīng)的下標處,接著將表示實際持有元素的總數(shù)值的elementCount增加1,這里的實例變量elementCount同時扮演著兩個角色,一個是用于記錄Vector對象實際持有的元素總數(shù),另一個是用于作為Vector對象持有的底層數(shù)組對象的下標!
4、返回添加元素的結(jié)果
每次都會返回true,表示添加元素成功
add(int,E)方法分析
public void add(int index, E element) { insertElementAt(element, index); }
用于在指定下標處添加一個元素的方法,第一個參數(shù)index表示指定的下標,第二個參數(shù)element表示添加的元素
方法體中調(diào)用insertElementAt()方法,并將傳入的index、element兩個參數(shù)同時傳入insertElementAt()方法中,由insertElementAt()方法完成元素的添加
insertElementAt()方法分析
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++; }
用于在指定下標處添加1個元素的方法,第一參數(shù)obj表示添加的元素對象,第二個參數(shù)index表示指定的下標……(注意:這里的參數(shù)順序,真是老外思路),同樣由synchronized修飾,只有獲取到對象鎖的線程才能執(zhí)行該方法,未獲取到對象鎖的線程處于方法入口處,并處于blocked狀態(tài)
1、最先修改modCount值
實例變量modCount定義在父類AbstractList中,它用于防止容器類在多線程下使用,常稱為fail-fast機制i,此處將該值增加1,表示Vector對象持有的元素發(fā)生改變
2、檢查傳入的下標值是否合法
如果傳入的下標值index大于Vector對象實際持有的元素總數(shù)elementCount值,此時拋出ArrayIndexOutOfBoundsException對象,并提示用戶"index > elementCount"(替換為實際值)
3、檢查是否需要擴容
調(diào)用ensureCapacityHelper()方法,同時將elementCount+1的值傳了進去
4、拷貝數(shù)組元素,騰出一個空余位置
通過System的靜態(tài)方法arraycopy()完成元素的拷貝,arraycopy()的第一個參數(shù)為源數(shù)組對象,第二個參數(shù)為源數(shù)組對象的起始下標(從哪個元素開始拷貝),第三個參數(shù)為目標數(shù)組對象,第四個參數(shù)為目標數(shù)組對象的起始下標(從哪個元素開始粘貼),第五個參數(shù)為需要拷貝的元素數(shù)量!此處只需挪出一個位置,即可存放即將要插入的元素!
5、向指定位置插入元素
已經(jīng)騰出空余空間,只需將元素插入到數(shù)組的指定下標處即可
6、元素總數(shù)增加
Vector對象持有的elementCount增加1
addElement()方法分析
public synchronized void addElement(E obj) { modCount++; ensureCapacityHelper(elementCount + 1); elementData[elementCount++] = obj; }
同樣為synchronized修飾,添加一個元素的方法,有一點和add()方法不同,它沒有返回值…………,幾乎都一樣,這里不再冗余分析
addAll()方法分析
public synchronized boolean addAll(Collection<? extends E> c) { modCount++; Object[] a = c.toArray(); int numNew = a.length; ensureCapacityHelper(elementCount + numNew); System.arraycopy(a, 0, elementData, elementCount, numNew); elementCount += numNew; return numNew != 0; }
用于添加多個元素的方法,傳入的參數(shù)為Collection對象,表示持有多個元素的集合對象,本身方法同樣是由synchronized修飾
1、為modCount值增加1,表示Vecor對象持有的元素發(fā)生改變,fail-fast機制會用到該值
2、先將Collection對象,轉(zhuǎn)換成一個Object[]數(shù)組對象,并由局部變量a負責保存
3、獲取轉(zhuǎn)換數(shù)組后的長度,由局部變量numNew負責保存
4、調(diào)用ensureCpacityHelper()方法,將需要的新容量(elementCount+numNew)傳入進去,檢查現(xiàn)有數(shù)組容量能否存儲下新的元素數(shù)量
5、使用System的靜態(tài)方法arraycopy(),復制新的元素到舊的數(shù)組中,完成添加元素行為
6、更新elementCount總數(shù)
7、返回添加結(jié)果,只要添加的數(shù)量不是0,說明添加元素成功
addAll(int,Collection)方法分析
public synchronized boolean addAll(int index, Collection<? extends E> c) { modCount++; if (index < 0 || index > elementCount) throw new ArrayIndexOutOfBoundsException(index); Object[] a = c.toArray(); int numNew = a.length; ensureCapacityHelper(elementCount + numNew); int numMoved = elementCount - index; if (numMoved > 0) System.arraycopy(elementData, index, elementData, index + numNew, numMoved); System.arraycopy(a, 0, elementData, index, numNew); elementCount += numNew; return numNew != 0; }
在指定位置添加多個元素的方法,傳入的參數(shù)index表示指定的下標、傳入的參數(shù)c表示要添加元素集合對象,同樣為synchronized修飾,只有獲取到對象鎖的線程才能執(zhí)行該方法,java的線程間同步做的真的太好!
1、更新modCount值,用于fail-fast機制檢測
2、檢查下標范圍是否合法,不合法拋出ArrayIndexOutOfBoundsException提示用戶
3、Collection對象轉(zhuǎn)數(shù)組對象
4、獲取轉(zhuǎn)換后數(shù)組對象的長度
5、確認是否需要擴容數(shù)組容量
6、計算需要移動元素的數(shù)量
7、確定需要移動元素,使用System的靜態(tài)方法arraycopy()移動元素
8、將新插入的所有元素,都賦值到elementData數(shù)組中,就從指定下標index開始
9、更新元素總數(shù)值
10、返回添加結(jié)果,不為0,即為True
ListItr中的add()方法分析
public void add(E e) { int i = cursor; synchronized (Vector.this) { checkForComodification(); Vector.this.add(i, e); expectedModCount = modCount; } cursor = i + 1; lastRet = -1; }
迭代器對象,可以添加元素,必須可以
1、先將遍歷到哪個元素的游標保存到局部變量i中
2、只有獲取到對象鎖的線程,才能執(zhí)行該代碼塊,此處仍為當前Vector對象作為對象鎖
檢查fail-fast機制
使用Vector的add(int,E)方法進行添加元素
更新一個預期值,expetcedModCount,這個也是用于fail-fast機制檢測用的
3、更新游標值,增加1
4、更新迭代器對象持有的lastRet值為-1,表示上一次并沒有進行遍歷元素的行為
總結(jié)
1、Vector使用了一手synchronized,這也是導致效率變低的原因
2、假設(shè)1個線程執(zhí)行插入操作需要5s,而其它n個線程操作任意一個Vecotor的方法,因為沒有持有當前的Vector對象鎖,所有的n個線程都被阻塞了……,同一時刻,只有1個線程能操作Vector的1個方法
3、如果只是讀的操作,完全沒有必要線程間同步啊,畢竟讀的內(nèi)存值一直沒變啊,所以后來大牛不建議使用Vector
以上就是基于java構(gòu)造方法Vevtor添加元素源碼分析的詳細內(nèi)容,更多關(guān)于java構(gòu)造方法Vevtor的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
在?Spring?Boot?中使用?Quartz?調(diào)度作業(yè)的示例詳解
這篇文章主要介紹了在?Spring?Boot?中使用?Quartz?調(diào)度作業(yè)的示例詳解,在本文中,我們將看看如何使用Quartz框架來調(diào)度任務(wù),Quartz支持在特定時間運行作業(yè)、重復作業(yè)執(zhí)行、將作業(yè)存儲在數(shù)據(jù)庫中以及Spring集成,需要的朋友可以參考下2022-07-07Mybatis MapperScannerConfigurer自動掃描Mapper接口生成代理注入到Spring的方法
這篇文章主要給大家介紹了關(guān)于Mybatis MapperScannerConfigurer自動掃描將Mapper接口生成代理注入到Spring的相關(guān)資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下2019-03-03Java中設(shè)置session超時(失效)的三種方法
這篇文章主要介紹了Java中設(shè)置session超時(失效)的三種方法,本文講解了在web容器中設(shè)置、在工程的web.xml中設(shè)置、通過java代碼設(shè)置3種方法,需要的朋友可以參考下2015-07-07