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.mzph.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;否则就会存储在参数…