Java最佳實踐– Vector vs ArrayList vs HashSet

在使用Java編程語言時,我們將繼續討論與建議的實踐有關的系列文章,我們將在三個最常用的Collection實現類之間進行性能比較。 為了使事情變得更現實,我們將在多線程環境下進行測試,以討論和演示如何將Vector , ArrayList和/或HashSet用于高性能應用程序。

所有討論的主題均基于用例,這些用例來自于電信行業的關鍵任務超高性能生產系統的開發。

在閱讀本文的每個部分之前,強烈建議您參考相關的Java API文檔以獲取詳細信息和代碼示例。

所有測試均針對具有以下特征的Sony Vaio進行:

  • 系統:openSUSE 11.1(x86_64)
  • 處理器(CPU):Intel(R)Core(TM)2 Duo CPU T6670 @ 2.20GHz
  • 處理器速度:1,200.00 MHz
  • 總內存(RAM):2.8 GB
  • Java:OpenJDK 1.6.0_0 64位

應用以下測試配置:

  • 并發工作線程數:50
  • 每個工作人員測試重復次數:100
  • 整體測試次數:100

向量vs ArrayList vs HashSet

Java開發人員必須執行的最常見任務之一是從Collections中存儲和檢索對象。 Java編程語言提供了一些具有重疊和獨特特征的Collection實現類。 Vector , ArrayList和HashSet可能是最常用的。

但是,使用Collection實現類 (特別是在多線程環境中)可能會很棘手。 默認情況下,它們中的大多數不提供同步訪問。 因此,以并行方式更改Collection的內部結構(插入或縮回元素)肯定會導致錯誤。

這里將要討論的案例場景是通過上述每個Collection實現類的元素進行多個Thread的插入,縮回和迭代。 我們將演示如何在多線程環境中正確利用上述集合實現類,并提供相關的性能比較表,以顯示在每個測試用例中哪個性能更好。

為了進行票價比較,我們將假定不允許使用NULL元素,并且我們不介意Collections中元素的順序。 此外,由于矢量是唯一集合實現類我們的測試組提供了默認的同步訪問,同步的ArrayList和HashSet的 集合實現類將使用Collections.synchronizedListCollections.synchronizedSet靜態方法來實現。 這些方法提供了指定Collection實現類的“包裝”同步實例,如下所示:

  • 列表syncList = Collections.synchronizedList(new ArrayList());
  • 設置syncSet = Collections.synchronizedSet(new HashSet());

測試用例#1 –在集合中添加元素

對于第一個測試用例,我們將有多個線程在每個Collection實現類中添加String元素。 為了保持String元素之間的唯一性,我們將如下所示構造它們:

  • 靜態的第一部分,例如“ helloWorld”
  • 工作線程ID,請記住,我們有50個并發運行的工作線程
  • worker線程測試重復次數,請記住,每個worker線程每次測試執行100次測試重復

對于每個測試運行,每個工作線程將插入100個String元素,如下所示:

  • 對于第一次測試重復
    • 工作線程1將插入String元素:“ helloWorld-1-1”
  • 對于第二次測試重復
    • 工作線程1將插入String元素:“ helloWorld-1-2”
  • 等等...

在每次測試運行結束時,每個Collection實現類都將填充5000個不同的String元素。

下面我們展示了上述三個Collection實現類之間的性能比較表

橫軸表示測試運行的次數,縱軸表示每次測試運行的每秒平均事務數(TPS)。 因此,較高的值更好。 如您所見,在向Vector和ArrayList Collection實現類添加元素時,它們的執行效果幾乎相同。 另一方面, HashSet Collection實現類的性能稍差,主要是由于內部結構和哈希生成機制更加復雜。

測試案例2 –從集合中刪除元素

對于第二個測試用例,我們將有多個線程從每個Collection實現類中刪除String元素。 所有集合實現類都將使用來自先前測試用例的String元素進行預填充。 為了刪除元素,我們將為每個Collection實現類在所有工作線程之間利用共享的Iterator實例。 對Iterator實例的同步訪問也將實現。 每個工作線程都將刪除Collection實現類的下一個可用元素,并發出“ next()”和“ remove()” 迭代器操作(以避免ConcurrentModificationException )。 下面是上述測試用例的性能比較表。

橫軸表示測試運行的次數,縱軸表示每次測試運行的每秒平均事務數(TPS)。 因此,較高的值更好。 同樣,從中移除String元素時, Vector和ArrayList Collection實現類的性能幾乎相同。 另一方面, HashSet Collection實現類的性能遠遠優于Vector和ArrayList ,平均速度為678000 TPS。

在這一點上,我們必須指出,通過使用Vector和ArrayList Collection實現類的“ remove(0)”方法刪除String元素,與使用同步共享Iterator實例相比,我們獲得了更好的性能結果。 我們之所以演示同步共享Iterator實例“ next()”和“ remove()”操作方法,是為了維持三個Collection實現類之間的票價比較。

重要的提醒

我們的測試用例場景要求我們從每個Collection實現類中刪除第一個元素。 盡管如此,我們必須指出,這對于Vector和ArrayList Collection實現類是最壞的情況。 作為我們的讀者之一,詹姆斯·沃森(James Watson)成功評論了TheServerSide的相關帖子

原因是在ArrayList和Vecrtor上,如果刪除了除最后一個元素以外的任何元素(最后一個元素是索引為:size – 1的元素),則remove()方法將導致System.arraycopy()調用。 刪除第一個元素意味著將復制數組的整個其余部分,這是一個O(n)操作。 由于測試刪除了列表中的所有元素,因此完整測試變為O(n ^ 2)(緩慢)。

HashSet remove不執行任何此類數組副本,因此它的刪除時間為O(1)或恒定時間。 對于完整測試,則為O(n)(快速)。 如果重寫測試以從ArrayList和Vector中刪除最后一個元素,則性能可能與HashSet相似。

因此,我們將再次進行此測試,從Vector和ArrayList Collection實現類中刪除最后一個元素,因為我們假定Collections中元素的順序并不重要。 性能結果如下所示。

橫軸表示測試運行的次數,縱軸表示每次測試運行的每秒平均事務數(TPS)。 因此,較高的值更好。 不出所料,從其中刪除String元素時,所有Collection實現類的性能幾乎相同。

測試案例#3 –迭代器

對于第三個測試用例,我們將有多個工作線程在每個Collection實現類的元素上進行迭代。 每個工作線程將使用Collection “ iterator()”操作檢索對Iterator實例的引用,并使用Iterator “ next()”操作遍歷所有可用的Collection元素。 所有Collection實現類都將使用第一個測試用例的String值預先填充。 下面是上述測試用例的性能比較表。

橫軸表示測試運行的次數,縱軸表示每次測試運行的每秒平均事務數(TPS)。 因此,較高的值更好。 與ArrayList Collection實現類相比, Vector和HashSet Collection實現類的性能均較差。 Vector平均獲得68 TPS,而HashSet平均獲得9200 TPS。 另一方面,到目前為止, ArrayList的性能優于Vector和HashSet ,平均速度為421000 TPS。

測試案例4 –添加和刪除元素

對于我們的最終測試用例,我們將實現測試用例1和測試用例2場景的組合。 一組輔助線程將向每個Collection實現類插入String元素,而另一組輔助線程將從其中撤回String元素。

在組合(添加和縮回元素)操作中,無法使用用于刪除元素的同步共享Iterator實例方法。 由于Collection的內部結構在不斷變化,因此從單個Collection中同時添加和刪除元素可避免使用共享的Iterator實例。 對于Vector和ArrayList Collection實現類,可以通過使用“ remove(0)”操作來繞過上述限制,該操作將從Collection內部存儲器中收回第一個元素。 不幸的是, HashSet Collection實現類不提供此類功能。 我們建議的使用HashSet Collection實現類為組合操作獲得最大性能的方法如下:

  • 使用兩個不同的HashSet,一個用于添加元素,另一個用于撤回
  • 實現一個“控制器” 線程 ,該線程將在“收回” HashSet為空時交換上述HashSet類的內容。 “控制器” 線程可以實現為常規TimerTask ,可以定期檢查“縮回” HashSet的內容,并在需要時執行交換
  • 交換兩個HashSet時,應為“收回” HashSet創建一個共享的Iterator實例。
  • 所有撤消元素的輔助線程應等待“撤消” HashSet充滿元素并在交換后得到通知

以下是顯示建議實施的代碼段:

全球宣言:

Set<string> s = new HashSet<string>(); // The HashSet for retracting elements
Iterator<string> sIt = s.iterator(); // The shared Iterator for retracting elements
Set<string> sAdd = new HashSet<string>(); // The HashSet for adding new elements
Boolean read = Boolean.FALSE; // Helper Object for external synchronization and wait – notify functionality when retracting elements from the “s” HashSet
Boolean write = Boolean.FALSE; // Helper Object for external synchronization when writing elements to the “sAdd” HashSet

用于將元素添加到“ sAdd” HashSet的代碼 :

synchronized(write) {sAdd.add(“helloWorld” + "-" + threadId + "-" + count);
}

用于從“ s” HashSet中撤回元素的代碼:

while (true) {synchronized (read) {try {sIt.next();sIt.remove();break;} catch (NoSuchElementException e) {read.wait();}}
}

“控制器”類代碼:

public class Controller  extends TimerTask {public void run() {try {performSwap();} catch (Exception ex) {ex.printStackTrace();}}private void performSwap() throws Exception {synchronized(read) {if(s.isEmpty()) {synchronized(write) {if(!sAdd.isEmpty()) {Set<string> tmpSet;tmpSet = s;s = sAdd;sAdd = tmpSet;sIt = s.iterator();read.notifyAll();}}}}}}

最后,安排“控制器” TimerTask的代碼

Timer timer = new Timer();
timer.scheduleAtFixedRate(new Controller(), 0, 1);

我們應該先啟動“控制器”任務,然后再啟動對相關HashSet進行讀寫的輔助線程 。

請記住,對于Vector和ArrayList Collection實現類,我們使用了“ remove(0)”操作來收回元素。 以下是上述Collection實現類的代碼段:

while (true) {try {vector.remove(0);break;} catch (ArrayIndexOutOfBoundsException e) {}
}while (true) {try {syncList.remove(0);break;} catch (IndexOutOfBoundsException e) {}
}

下面是上述測試用例的添加部分的性能比較表。

以下是上述測試案例的收回部分的性能比較表。

橫軸表示測試運行的次數,縱軸表示每次測試運行的每秒平均事務數(TPS)。 因此,較高的值更好。 Vector和ArrayList Collection實現類在添加和撤消元素時的性能幾乎相同。 另一方面,對于元素添加測試用例,與Vector和ArrayList實現相比,我們建議的實現(帶有“添加”和“縮回” HashSet對)的性能略遜一籌。 但是,對于元素撤回測試用例,我們的“添加”和“撤回” HashSet對實現比Vector和ArrayList實現都要好,平均得分為6000 TPS。

快樂編碼

賈斯汀

相關文章 :
  • Java最佳實踐–多線程環境中的DateFormat
  • Java最佳實踐–高性能序列化
  • Java最佳實踐–字符串性能和精確字符串匹配
  • Java最佳實踐–隊列之戰和鏈接的ConcurrentHashMap
  • Java最佳實踐– Char到Byte和Byte到Char的轉換
相關片段:
  • ArrayList大小示例
  • 將Collection的所有元素插入特定的ArrayList索引
  • 在HashSet示例中檢查元素是否存在
  • HashSet迭代器示例
  • Java Map示例
  • 將元素添加到Vector示例的指定索引

翻譯自: https://www.javacodegeeks.com/2010/08/java-best-practices-vector-arraylist.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/374825.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/374825.shtml
英文地址,請注明出處:http://en.pswp.cn/news/374825.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

iOS:圖片上傳時兩種圖片壓縮方式的比較

上傳圖片不全面的想法&#xff1a;把圖片保存到本地,然后把圖片的路徑上傳到服務器&#xff0c;最后又由服務器把路徑返回&#xff0c;這種方式不具有擴展性&#xff0c;如果用戶換了手機&#xff0c;那么新手機的沙盒中就沒有服務器返回的圖片路徑了&#xff0c;此時就無法獲取…

7-17 爬動的蠕蟲 (15 分)

一條蠕蟲長1寸&#xff0c;在一口深為N寸的井的底部。已知蠕蟲每1分鐘可以向上爬U寸&#xff0c;但必須休息1分鐘才能接著往上爬。在休息的過程中&#xff0c;蠕蟲又下滑了D寸。就這樣&#xff0c;上爬和下滑重復進行。請問&#xff0c;蠕蟲需要多長時間才能爬出井&#xff1f;…

淺談泛型之泛型方法

實際不用多說只舉2個例子就行: //例1 static void fromArrayToCollection(Object[] a, Collection<?> c) {for (Object o : a) { c.add(o); // 編譯錯誤,錯誤原因也很簡單,<?>是無上下界的通配符泛型,所以編譯器根本無法確認類型} } //例2 static <T> void…

Android特效 五種Toast詳解

Toast是Android中用來顯示顯示信息的一種機制&#xff0c;和Dialog不一樣的是&#xff0c;Toast是沒有焦點的&#xff0c;而且Toast顯示的時間有限&#xff0c;過一定的時間就會自動消失。而且Toast主要用于向用戶顯示提示消息&#xff0c;接下來巴士為大家總結了Android五種To…

Java最佳實踐–高性能序列化

在使用Java編程語言時&#xff0c;我們將繼續討論與建議的實踐有關的系列文章&#xff0c;我們將討論并演示如何將對象序列化用于高性能應用程序。 所有討論的主題均基于用例&#xff0c;這些用例來自于電信行業的關鍵任務超高性能生產系統的開發。 在閱讀本文的每個部分之前…

7-18 二分法求多項式單根 (20 分)

二分法求函數根的原理為&#xff1a;如果連續函數f(x)在區間[a,b]的兩個端點取值異號&#xff0c;即f(a)f(b)<0&#xff0c;則它在這個區間內至少存在1個根r&#xff0c;即f0。 二分法的步驟為&#xff1a; 檢查區間長度&#xff0c;如果小于給定閾值&#xff0c;則停止&a…

java只使用try和finally不使用catch的原因和場景

JDK并發工具包中&#xff0c;很多異常處理都使用了如下的結構&#xff0c;如AbstractExecutorService&#xff0c;即只有try和finally沒有catch。 class X {private final ReentrantLock lock new ReentrantLock();// ...public void m(){lock.lock(); // block until condi…

Java 7:嘗試資源

本文研究try-with-resources語句的用法。 這是一個聲明一個或多個資源的try語句。 資源是一個對象&#xff0c;程序完成后必須將其關閉。 try-with-resources語句可確保在語句末尾關閉每個資源。 任何實現java.lang.AutoCloseable或java.io.Closeable接口的對象都可以用作資源。…

Spring學習(19)--- Schema-based AOP(基于配置的AOP實現) --- 配置切面aspect

Spring所有的切面和通知器都必須放在一個<aop:config>內&#xff08;可以配置包含多個<aop:config>元素&#xff09;&#xff0c;每個<aop:config>包含pointcut&#xff0c;advisor和apsect元素。ps&#xff1a;他們必須按照這個順序進行聲明 <aop:pointc…

2021-10-08

word文檔&#xff1a;.doc .docx 需求文檔、架構文檔、接口文檔、詳設文檔一般都是用word編寫。 Excel表格&#xff1a;.xls、.xlsx’&#xff0c;.csv 測試用例 PPT幻燈片&#xff1a;.ppt、*.pptx 版本不同 可執行文件&#xff08;windows系統&#xff09;&#xff1a; *.exe…

UITableViewCell 選中的狀態小技巧

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {[super setSelected:selected animated:animated]; //cell 沒被選中時 隱藏這個 _leftImageViewself.leftImageView.hidden !selected; //選中text變紅 不然變灰色self.textLabel.textColor selected ? [UICol…

Spring和AspectJ的領域驅動設計

在JavaCodeGeeks主持的上一篇文章中&#xff0c;我們的JCG合作伙伴 Tomasz Nurkiewicz介紹了使用State設計模式進行領域驅動設計的介紹 。 在該教程的最后&#xff0c;他承認他省略了如何將依賴項&#xff08;DAO&#xff0c;業務服務等&#xff09;注入域對象的過程。 但是&am…

BZOJ 3143 HNOI2013 游走 高斯消元 期望

這道題是我第一次使用高斯消元解決期望類的問題&#xff0c;首發A了&#xff0c;感覺爽爽的.... 不過筆者在做完后發現了一些問題&#xff0c;在原文的后面進行了說明。 中文題目&#xff0c;就不翻大意了&#xff0c;直接給原題&#xff1a; 一個無向連通圖&#xff0c;頂點從…

VS2019安全函數scanf_s問題

VS2017、VS2019等安全函數scanf_s問題&#xff1a; scanf()、gets()、fgets()、strcpy()、strcat() 等都是C語言自帶的函數&#xff0c;它們都是標準函數&#xff0c;但是它們都有一個缺陷&#xff0c;就是不安全&#xff0c;可能會導致數組溢出或者緩沖區溢出&#xff0c;讓黑…

eclipse啟動tomcat, http://localhost:8080無法訪問的解決方案

問題:&#xff1a; tomcat在eclipse里面能正常啟動&#xff0c;但在瀏覽器中訪問http://localhost:8080/不能訪問tomcat管理頁面&#xff0c;且報404錯誤。同時其他項目頁面也不能訪問。訪問的時候出現下列頁面: 現在關閉eclipse里面的tomcat&#xff0c;在tomcat安裝目錄下雙擊…

GWT EJB3 Maven JBoss 5.1集成教程

大家好&#xff0c; 在本文中&#xff0c;我們將演示如何正確集成GWT和EJB3 &#xff0c;以實現示例項目&#xff0c;使用maven進行構建并將其部署在JBoss 5.1應用服務器上。 實際上&#xff0c;您可以輕松地更改maven構建文件中的依賴關系&#xff0c;并將項目部署到您喜歡的…

VS2019注釋整段代碼

VS2019注釋整段代碼 1.注釋 先CTRLK&#xff0c;然后CTRLC 2.取消注釋&#xff1a; 先CTRLK&#xff0c;然后CTRLU 順便寫一下&#xff1a; VS code注釋整段代碼 Alt Shift A 注釋 CodeBlocks&#xff1a; CtrlShiftC注釋掉當前行或選中部分&#xff0c; CtrlShiftX解除注釋…

linux中的開機和關機命令

與關機、重新啟動相關的命令 * 將數據同步寫入硬盤中的命令 sync * 慣用的關機命令 shutdown * 重新啟動、關機 reboot halt poweroff sync 強制將內存中的數據寫入到硬盤當中。因為linux系統中&#xff0c;數據會緩存在內存當中&#xff0c;所以為了保證數據完整保存在硬盤…

如何在不到1ms的延遲內完成100K TPS

馬丁湯普森&#xff08;Martin Thompson&#xff09;和邁克爾巴克&#xff08;Michael Barker&#xff09;討論了通過采用一種新的基礎架構和軟件方法來構建HPC金融系統&#xff0c;以不到1ms的延遲處理超過100K TPS的問題。 一些技巧包括&#xff1a; 了解平臺 建模領域 明…

獲取時間C語言-按秒數

兩部分&#xff1a; 1.獲取秒數 2.獲取“年-月-日-時-分-秒” 1.獲取秒數 #include<time.h>//包含的頭文件int GetTime() {time_t t;t time(NULL);//另一種寫法是//time(t);//當time&#xff08;&#xff09;內參數為空時結果直接輸出&#xff0c;否則就會存儲在參數…