如何在 Java 中同步 ArrayList
ArrayList
是 Java 中一个非常有用的 Collection,我想也是最常用的一个,但它不是同步的。 这是什么意思? 这意味着我们不能在多个线程之间共享 ArrayList 的实例,如果它们不仅从中读取而且还写入或更新元素。 那么如何 同步ArrayList 呢? 好吧,我们稍后会讲到这个,但是我们是否首先想到为什么 ArrayList 不同步? 既然多线程是Java的核心优势,几乎所有的Java程序都不止一个线程,为什么Java设计者不让 ArrayList 在这样的环境下使用更方便呢?
答案在于性能,与同步相关的性能成本,并且使 ArrayList 同步会使它变慢。 所以,他们肯定考虑过它并让 ArrayList 保持非同步以保持快速,但与此同时他们提供了使其同步的简单方法,这就是我们将在本篇文章中学习的内容。
JDK Collections 类有几种方法来创建同步的 List、Set 和 Map,我们将使用 Collections.synchronizedList()
方法使我们的 ArrayList 同步。 此方法接受一个 List,它可以是 List 接口的任何实现,例如 ArrayList、LinkedList,并返回由指定列表支持的同步(线程安全)列表。 所以你也可以使用这个技巧在Java中让 LinkedList 同步并且线程安全。
同步列表和迭代
在多个线程之间共享 ArrayList 的主要挑战之一是如何处理一个线程试图访问被其他线程删除的元素的情况。 如果我们使用 get(index)
或 remove(index)
方法来检索或删除元素,那么其他线程也可能正在删除其他元素。
这意味着如果不首先检查列表的大小,我们将无法可靠地调用 get(index)
或 remove(index)
,然后我们还需要在对 size()
和 remove(int index)
的调用之间提供额外的同步。
为了保证串行访问,对支持列表的所有访问都通过返回列表完成,这一点至关重要,用户在迭代返回列表时必须手动同步返回列表,如以下示例代码所示:
List list = Collections.synchronizedList(new ArrayList());
...
synchronized(list) {
Iterator i = list.iterator(); // Must be in synchronized block
while (i.hasNext())
foo(i.next());
}
正如 Java 文档中所建议的,不遵循此建议可能会导致不确定的行为。 如果提供的 ArrayList 是可序列化的,则该列表也将是可序列化的。
用于同步 ArrayList 的 Java 程序
这是在 Java 中同步 ArrayList 的完整示例。 如果大家看的话,我们已经创建了一个字符串列表并向其中添加了几个元素。 然后我们将这个 ArrayList 传递给 Collections.synchronizedList()
方法,它返回一个线程安全的同步版本的支持列表。
现在可以在多个线程之间安全地共享此列表,但在从 ArrayList 中检索或删除元素时需要小心一点。 为了安全访问,我们应该使用 Iterator 从列表中获取和删除元素,并且以同步方式进行,如本例所示。
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
/**
* 如何在 Java 中同步 ArrayList
*/
public class SynchronizedArrayListDemo {
public static void main(String args[]) {
// 一个不同步的 ArrayList List<String>
listOfSymbols = new ArrayList<String>();
listOfSymbols.add("RELIANCE");
listOfSymbols.add("TATA");
listOfSymbols.add("TECHMAH");
listOfSymbols.add("HDFC");
listOfSymbols.add("ICICI");
// 同步 ArrayList
listOfSymbols = Collections.synchronizedList(listOfSymbols);
// 在迭代同步列表时,我们必须对其进行同步以避免非确定性行为
synchronized (listOfSymbols) {
Iterator<String> myIterator = listOfSymbols.iterator();
while (myIterator.hasNext()) {
System.out.println(myIterator.next());
}
}
}
}
这就是关于如何在 Java 中同步 ArrayList 的全部内容。 如大家所知,由于 Collections.synchronizedList()
方法,在 Java 中执行此操作非常容易,但是在从 List 中检索和删除对象时需要更加小心。
顺便说一句,我们可以使用 Vector 和 CopyOnWriteArrayList 形式的更多选项。
Vector
是一个非常古老的类,但在 Java 1.4 中被改造以实现 List 接口,更重要的是它是同步的,因此我们不需要再次同步它。 顺便说一句,在使用 Vector 时,请确保我们通过 List 接口使用它,而不是使用遗留方法,否则以后将无法替换实现。
另一方面,CopyOnWriteArrayList
是 Java 中并发集合类的一部分,并且比 Vector 和 ArrayList 更具可扩展性。 如果我们的程序主要从 List 读取并偶尔更新它,那么这可能是正确的选择。
相关文章
在 Java 中获取文件大小
发布时间:2023/05/01 浏览次数:139 分类:Java
-
Java 提供了不同的方法来获取文件的字节大小。 本教程演示了在 Java 中获取文件大小的不同方法。使用 Java IO 的文件类获取文件大小 Java IO 包的 File 类提供了以字节为单位获取文件大小的功能。
Java 中的文件分隔符
发布时间:2023/05/01 浏览次数:108 分类:Java
-
本篇文章介绍了 Java 中的文件分隔符。Java 中的文件分隔符 文件分隔符是用来分隔目录的字符; 例如,Unix 使用 /,Windows 使用 \ 作为文件分隔符。
Java 中的文件过滤器
发布时间:2023/05/01 浏览次数:193 分类:Java
-
本篇文章介绍如何在 Java 中使用 FileFilter。FileFilter 用于过滤具有特定扩展名的文件。 Java内置包IO和Apache Commons IO为FileFilter提供了类和接口来进行文件过滤操作。
Java 获取 ISO 8601 格式的当前时间戳
发布时间:2023/05/01 浏览次数:132 分类:Java
-
本篇文章介绍了 ISO 8601 日期格式、其重要性及其在 Java 中的使用。 它还列出了一些优点来强调为什么应该使用 ISO 格式来表示日期。
在 Java 中获取数组的子集
发布时间:2023/05/01 浏览次数:142 分类:Java
-
本篇文章介绍了几种在 Java 中获取数组子集的方法。使用 Arrays.copyOf() 方法获取数组的子集 使用 Arrays.copyOfRange() 方法获取数组的子集
用 Java 填充二维数组
发布时间:2023/05/01 浏览次数:110 分类:Java
-
二维数组是基于表结构的,即行和列,填充二维数组不能通过简单的添加到数组操作来完成。 本篇文章介绍如何在 Java 中填充二维数组。
计算 Java 数组中的重复元素
发布时间:2023/05/01 浏览次数:202 分类:Java
-
本篇文章介绍Java计算数组中重复元素的方法。计算 Java 数组中的重复元素。我们可以创建一个程序来计算数组中的重复元素。 该数组可以是未排序的,也可以是已排序的。
Java 中 List 和 Arraylist 的区别
发布时间:2023/05/01 浏览次数:90 分类:Java
-
表示为单个单元的一组单个对象称为集合。 在 Java 中,Collection 是一个具有多个已定义接口和类的框架,用于将一组对象表示为一个单元。 它允许我们操纵