返回介绍

8.4 调试进入 ArrayList 内部

发布于 2024-08-21 22:20:21 字数 1772 浏览 0 评论 0 收藏 0

首先,我们需要理解ArrayList的工作方式。在ArrayList初始化时,默认会分配10个数组空间。当数组空间消耗完毕后,ArrayList就会进行自动扩容。在每次add()操作时,系统总要事先检查一下内部空间是否满足所需的大小,如果不满足,就会扩容,否则就可以正常添加元素。

多线程共同访问ArrayList的问题在于:在ArrayList容量快用完时(只有1个可用空间),如果两个线程同时进入add()函数,并同时判断认为系统满足继续添加元素而不需要扩容,进而两者都不会进行扩容操作。之后,两个线程先后向系统写入自己的数据,那么必然有一个线程会将数据写到边界外,而产生这个ArrayIndexOutOfBoundsException。

基于上述原理,我们在ArrayList.add()函数中设置断点如图8.9所示。

图8.9 ArrayList.add()的断点设置

这个断点意味着在非主线程中(这里就是t1和t2了),当进入add()函数后,如果当前ArrayList的容量为9(当前的最大容量为10),则触发断点。之所以这么设置,是因为当容量没有饱和时,显然不会发生这个ArrayIndexOutOfBoundsException的问题,因此可以直接忽略这些情况。

接着,选中t1线程,让它进行容量检查,并让它停止在追加元素的语句前,如图8.10所示。

图8.10 t1线程完成容量检查

接着,在t1增加元素之前,选中t2线程,并让t2进入add()函数,完成进行容量检查,如图8.11所示。

图8.11 t2完成容量检查

此时,t1和t2都认为ArrayList中的容量是满足它们的需求的,因此,它们都准备开始追加元素。让我们先选择t1,完成追加,如图8.12所示。

图8.12 t1完成元素追加

在t1追加完成后,t2并不知道数据空间实际上已经用完了。而之前的容量检查告诉t2,你可以继续追加元素,因此,t2还会义无反顾地继续执行后续追加操作。选择t2,让t2进行元素追加,此时,当t2试图向ArrayList追加元素时,追加操作并没有如我们预期一样完成,因为,此时,size的值已经超过了elementData的边界。如图8.13所示,可以看到ArrayIndexOutOfBoundsException异常位于t2线程中。

图8.13 t2线程发生异常

让t2继续往下执行的结果就是前文中那段异常信息,之后,t2线程就从线程列表中消失了(执行结束)。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文