ArrayList全面使用

Java 中的 ArrayList 是一个可调整大小的数组,可以在内存中增长或收缩。它是使用初始容量动态创建的。这意味着如果超过数组的初始容量,将自动创建一个容量更大的新数组,并将当前数组中的所有元素复制到新数组中。数组列表中的元素是从零索

ArrayList全面使用

Java 中的 ArrayList 是一个可调整大小的数组,可以在内存中增长或收缩。它是使用初始容量动态创建的。

这意味着如果超过数组的初始容量,将自动创建一个容量更大的新数组,并将当前数组中的所有元素复制到新数组中。

数组列表中的元素是从零索引开始放置的。也就是说,第一个元素将放置在 0 索引处,最后一个元素将放置在索引 (n-1) 处,其中 n 是 ArrayList 的大小。

Java ArrayList 在内部使用动态数组来存储元素或数据组。

ArrayList 的容量不会自动收缩。从列表中删除元素时,数组列表的大小可以自动缩小,但不能缩小容量。

Java中ArrayList类的层次结构图


ArrayList 类的层次结构图如下图所示。

如上面的层次结构图所示,ArrayList 类实现了 List 接口并扩展了实现 List 接口的 AbstractList(抽象List)。

Java ArrayList 类还实现了 3 个标记接口:Random Access(随机访问), Cloneable(克隆), Serializable(可序列化)。

标记接口是没有任何方法或任何成员变量的接口。它也被称为空接口,因为没有字段或方法。

Random Access接口

1. Random Access接口是一个标记接口,不定义任何方法或成员。它是在 Java 1.4 版本中引入的,用于优化列表性能。

2. RandomAccess 接口存在于 java.util 包中。

3. ArrayList 类实现了一个随机访问接口,以便我们可以以相同的速度访问任何随机元素。例如,数组列表中有一亿个对象。第一个元素是 x,第 10 个元素是 y,第 1 亿个元素是 z。

现在假设第一个元素 x 可以在 1 秒内访问。由于实现了随机访问接口,第10个元素和第1亿个元素也可以在1秒内访问。

因此,我们可以以相同或恒定的速度访问任何随机元素。如果我们经常的操作是检索操作,那么 ArrayList 是最佳选择。 Serializable接口

1. 可序列化接口是用于通过网络发送对象组的标记接口。它存在于 java.io 包中。

2.它有助于将数据从一个类发送到另一个类。通常,我们使用集合来保存对象并将其从一个地方转移到另一个地方。

为了支持此要求,每个集合类都已实现可序列化和可克隆。

Cloneable接口

1. java.lang 包中存在一个Cloneable接口。

2.它用于创建完全重复的对象。当数据或对象组来自网络时,接收方将创建重复的对象。

创建完全重复的对象的过程称为克隆。这是集合类的一个非常常见的要求。

ArrayList 在 Java 中的功能


Java中ArrayList类有几个特性。它们如下:

1. 可调整大小的数组:ArrayList 是一个可调整大小的数组或可增长的数组,这意味着 ArrayList 的大小可以在运行时增加或减少大小。创建 ArrayList 后,我们可以添加任意数量的元素。

2.基于索引的结构:它在java中使用基于索引的结构。

3.重复元素:数组列表中允许重复元素。

4. 空元素:可以将任意数量的空元素添加到数组列表中。

5.插入顺序:它维护Java中的插入顺序。即插入顺序保持不变。

6. 异构对象:除TreeSet 和TreeMap外,其他都允许异构对象。异构意味着不同的元素。

7. 已同步:ArrayList未同步。这意味着多个线程可以同时使用相同的ArrayList对象。

8. 随机访问:ArrayList 实现了随机访问,因为它使用基于索引的结构。因此,我们可以从任意位置获取、设置、插入和删除数组列表的元素。

9. 性能:在 ArrayList 中,变更类的操作很慢。

例如,如果数组列表有 500 个元素,我们删除了第 50 个元素,那么第 51 个元素将尝试获取第 50 个位置,同样,所有元素也是如此。因此,它消耗了大量的时间来进行移动操作。

Java ArrayList Constructor


Java ArrayList 类提供了三个构造函数,用于创建 ArrayList 的对象。它们是:

  • ArrayList()
  • ArrayList(int initialCapacity)
  • ArrayList(Collection c)

在Java中创建ArrayList类的对象非常简单。首先,我们将声明一个数组列表变量并调用数组列表构造函数来实例化 ArrayList 类的对象,然后将其分配给变量。

我们可以通过使用三个构造函数中的任何一个在 java 中创建 ArrayList 类的对象。让我们一起看看。

1. 创建 ArrayList 类实例的语法为:

代码语言:javascript代码运行次数:0运行复制
ArrayList al = new ArrayList();

它创建一个空的 ArrayList,默认初始容量为 10。在这个数组列表中,我们只能存储 10 个元素,如下图所示。

假设我们将第 10 位的第 11 个元素插入到数组列表中,内部会发生什么?

一旦 ArrayList 达到其最大容量,ArrayList 类就会自动创建一个容量更大的新数组。

New capacity = (current capacity*3/2) + 1 = 10*3/2 + 1 = 16

创建容量更大的新数组列表后,所有现有元素都将复制到新数组列表中,然后将新元素添加到其中。将引用重新分配给新的数组对象,如上图所示。

包含对象集合的旧默认数组列表将自动进入垃圾回收。同样,如果我们尝试插入第 17 个元素,新容量 = 16*3/2 + 1 = 25。

2. 我们还可以在创建 ArrayList 对象时初始化容量。创建具有初始容量的 ArrayList 类实例的语法如下:

代码语言:javascript代码运行次数:0运行复制
ArrayList al = new ArrayList(int initialCapacity);

它创建一个具有初始容量的空数组列表。如果知道初始容量,可以直接使用此方法;否则我们就应该采用默认值以提高系统的性能。

例如,假设我们的要求是在数组列表中添加 500 个元素,我们将创建如下的 ArrayList 对象:

代码语言:javascript代码运行次数:0运行复制
ArrayList list2 = new ArrayList(500);

3. 我们还可以通过集合参数的方式来初始化ArrayList 类。语法如下:

代码语言:javascript代码运行次数:0运行复制
ArrayList al = new ArrayList(Collection c);

它通过一个给定的集合 c 的元素来创建 ArrayList 对象。

例如:

代码语言:javascript代码运行次数:0运行复制
ArrayList list3 = new ArrayList(list1); // list1 is elements of collection.

在 Java 中创建泛型数组列表对象


Java 1.5 或更高版本还提供了我们可以指定 ArrayList 对象中元素的类型方法。例如,我们可以创建一个的字符串数组泛型列表对象,如下所示:

代码语言:javascript代码运行次数:0运行复制
    ArrayList<String> al = new ArrayList<String>(); // It can be used to store only String type. 

// The advantage of specifying a type is that when we try to add another type of element, it will give compile-time error.

or,
Creating a Generic ArrayList object can also be done in separate lines like this:
   ArrayList<String> arlist;    
         arlist = new ArrayList();

注意:我们不能使用原始数据类型作为类型。例如,ArrayList<int>是非法的。

Java ArrayList Initialization


在 Java 中初始化数组列表有三种方法。它们如下:

1. 使用 Arrays.asList:使用 asList() 方法初始化 ArrayList 的语法如下:

代码语言:javascript代码运行次数:0运行复制
ArrayList<Type> list = new ArrayList<Type>(Arrays.asList(Object o1, Object o2, .. so on));

For example:
  ArrayList<String> ar = new ArrayList<String>(Arrays.asList("A", "B", "C"))

2:使用普通方式:这是在java程序中初始化ArrayList的流行方法。初始化数组列表的语法如下:

代码语言:javascript代码运行次数:0运行复制
ArrayList<Type> obj = new ArrayList<Type>();   
  obj.add("Obj o1");
  obj.add("Obj o2");
  and so on.

3. 使用匿名内部类:在java中使用匿名内部类初始化ArrayList的语法为:

代码语言:javascript代码运行次数:0运行复制
ArrayList<Type> arl = new Arraylist<Type>() {{   
   add(Object o1);
   add(Object o2);
   add(Object o3);
   . . . . . . . . 
   . . . . . . . 
 }};

Java 中的 ArrayList Methods


ArrayList还提供了一些有用的方法。它们如下:

1.  boolean add(Object o):此方法用于在数组列表末尾添加一个元素。例如,如果你想在列表的末尾添加一个元素,你只需像这样调用 add() 方法:

代码语言:javascript代码运行次数:0运行复制
list.add("Shubh"); // This will add "Shubh" at the end of the list.

2. boolean addAll(Collection c): 此方法用于在列表末尾添加特定集合中的一组元素。例如,假设我们在 list2 中有一组元素,并希望在 list1 的末尾添加,我们将像这样调用此方法:

代码语言:javascript代码运行次数:0运行复制
 list1.addAll(list2);

3. boolean addAll(int index, Collection c):此方法用于在列表中的指定位置添加一组元素。例如:

代码语言:javascript代码运行次数:0运行复制
list1.addAll(2, list2): // Adding all elements of list2 at position index 2 in list1

4. void add(int index, Object o):用于在列表中的特定位置索引处添加一个元素。例如:

代码语言:javascript代码运行次数:0运行复制
list.add(3, "a"); // Adding element 'a' at position index 3 in list.

5. void addAll(int index, Object o):用于在列表中的特定位置添加特定元素。例如,假设我们想在列表中的位置 2 处放置一个特定的元素 “Shubh”,我们将调用 add(int index, Object o) 方法,如下所示:

代码语言:javascript代码运行次数:0运行复制
list.add(2,"Shubh"); // This will add "Shubh" at the second position.

让我们以一个基于上述 ArrayList add() 方法的示例程序为例。

程序源代码 1:

代码语言:javascript代码运行次数:0运行复制
package ArrayListTest; 
import java.util.ArrayList; 
public class AddExample 
{ 
public static void main(String[] args) 
{ 
// Create an object of the non-generic ArrayList. 
   ArrayList al = new ArrayList(); // list 1 with default capacity 10. 
    al.add("A"); 
    al.add("B"); 
    al.add(20); 
    al.add("A"); 
    al.add(null); 
   System.out.println(al); 

// Create an object of another non-generic ArrayList. 
   ArrayList al1 = new ArrayList(); // List 2.
    al1.add("a"); 
    al1.add("b"); 
    al1.add("c"); 

// Call addAll(Collection c) method using reference variable al to add all elements at the end of the list1.
    al.addAll(al1); 
    System.out.println(al); 

// Call addAll(int index, Collection c) method using reference variable al1 to add all elements at specified position 2. 
    al1.addAll(2, al); 
   System.out.println(al1); 
  } 
}
代码语言:javascript代码运行次数:0运行复制
Output: 
       [A, B, 20, A, null] 
       [A, B, 20, A, null, a, b, c] 
       [a, b, A, B, 20, A, null, a, b, c, c]

在前面的示例程序中,我们使用了重复元素、异构元素(即字符串和整数)和空元素。您还会注意到,当在特定位置添加指定元素时,右侧元素会向右移动一个位置。

移位后,对象引用变量将重新分配一个新的数组列表,如上图所示。由于转移,ArrayList也很耗时。

在输出中,我们得到了这个数组列表的方括号表示法。这是因为当我们尝试打印对象引用变量时,它会在内部调用 toString() 方法,如下所示:

代码语言:javascript代码运行次数:0运行复制
System.out.println(al); ------> System.out.println(al.toString());

5. void addAll(int index, Object o): 如果指定元素存在,它将从此列表中删除该元素的第一个匹配项。

6. void remove(int index):此方法从列表中的特定位置删除元素。请看下面的例子。

代码语言:javascript代码运行次数:0运行复制
list.remove("A");
list.remove(2); //  It will remove element from position 2.

7. void clear():clear() 方法用于从数组列表中删除所有元素。

8. void set(int index, Object o):set() 方法用指定的元素替换列表中特定位置的元素。例如,假设我们要将位置 2 的元素 “A” 替换为列表中的元素 “a”,我们将不得不将此方法调用为:

代码语言:javascript代码运行次数:0运行复制
list.set(2, "a");

让我们举一个示例程序,我们将使用 remove() 方法从列表中删除一个元素。

程序源代码 2:

代码语言:javascript代码运行次数:0运行复制
package ArrayListTest; 
import java.util.ArrayList; 
public class RemoveEx 
{ 
public static void main(String[] args) 
{ 
// Create a generic Arraylist object of String type. 
// This means the compiler will show an error if we try to put any other element than String. 
     ArrayList<String> al = new ArrayList<String>(); // Default capacity is 10. 

// Adding elements of String type. 
      al.add("A"); 
      al.add("B"); 
      al.add("C"); 
      al.add("D"); 
      al.add(null); 
      al.add("D"); 
  System.out.println(al);  

// Call remove() method to remove element D. 
     al.remove("D"); // removes the first occurrence of the specified element D at position 3, not from the position 5. 
     System.out.println(al); 
     al.remove(3); 
     System.out.println(al); 

// Call set method to replace the element D with a null element at position 3. 
     al.set(3, null); 
     System.out.println(al); 
  } 
}
代码语言:javascript代码运行次数:0运行复制
Output: 
        [A, B, C, D, null, D] 
        [A, B, C, null, D] 
        [A, B, C, D] 
        [A, B, C, null]

在此示例程序中,您将观察到,当从数组中删除或删除元素时,已删除的元素变为 null,但已删除元素占用的空插槽仍保留在数组中。

数组右侧的任何后续元素都会自动移动到左侧的一个位置,以填充被已删除元素占用的空插槽,对象引用变量 'al' 将被重新分配给新的数组列表,如上图所示。

9. Object get(int index)::它返回此列表中指定位置的元素。

10. int size():它返回列表的元素数。大小 表示数组列表中存在的元素数。容量是指存储元素的能力。

11. Object get(int index):如果列表中存在指定的元素,则返回 true,否则返回 false。请看下面的例子。

代码语言:javascript代码运行次数:0运行复制
String str = list.get(2);
int numberOfElements = list.size();
list.contains("A");

让我们看一个基于这些方法的示例程序。

程序源代码 3:

代码语言:javascript代码运行次数:0运行复制
package arrayListPrograms; 
import java.util.ArrayList; 
public class ArrayListTest 
{ 
public static void main(String[] args) 
{ 
 ArrayList al = new ArrayList(); 
  al.add("Apple"); 
  al.add("Orange"); 
  al.add("Banana"); 
  al.add("Gauva"); 
System.out.println(al); 

// Call get() method using object reference variable 'al' to get the specified element. 
// Since return type of get() method is String. Therefore, we will store it by using a fruitsName variable with data type String. 
     String fruitsName = al.get(2); 
     System.out.println(fruitsName); 

// Call size() method to get the number of elements present in the list. 
// Since return type of size method is an integer. Therefore, we will store it by using variable numberOfElements with data type integer. 
     int numberOfElements = al.size(); 
     System.out.println(numberOfElements); 

// Check apple element is present or not. 
   boolean check = al.contains("Apple"); 
   System.out.println(check); 
 } 
}
代码语言:javascript代码运行次数:0运行复制
Output: 
       [Apple, Orange, Banana, Gauva] 
       Banana 
       4 
       true

12. int indexOf(Object o):用于获取指定元素第一次出现的索引,如果列表中不存在该元素,则返回值 -1。

13. int lastIndexOf(Object o):用于获取列表中指定元素最后一次出现的索引。如果列表中不存在该元素,则返回 -1。例如:

代码语言:javascript代码运行次数:0运行复制
int pos = list.indexOf("Apple");
int lastPos = list.lastIndexOf(20);

程序源代码 4:

代码语言:javascript代码运行次数:0运行复制
package ArrayListTest; 
import java.util.ArrayList; 
public class Test 
{ 
public static void main(String[] args) 
{ 
 ArrayList<Integer> list = new ArrayList<Integer>(); 
  list.add(10); 
  list.add(20); 
  list.add(30); 
  list.add(40); 
 
 System.out.println(list); 
 int pos = list.indexOf(30); 
 System.out.println(pos); 
 
 int lastPos = list.lastIndexOf(40); 
 System.out.println(lastPos); 
 } 
}
代码语言:javascript代码运行次数:0运行复制
Output: 
       [10, 20, 30, 40]
       23

我们如何手动增加或减少 ArrayList 的当前容量?


1. ensureCapacity():此方法用于增加 ArrayList 的当前容量。由于当我们添加更多元素时,数组列表的容量会自动增加。但是要手动增加,请使用 ArrayList 类的 ensureCapacity() 方法。 2. trimTosize():trimTosize() 方法用于将 ArrayList 的容量修剪为 ArrayList 的当前大小。

代码语言:javascript代码运行次数:0运行复制
ArrayList<String> list = new ArrayList<String>(); // Here, list can hold 10 elements.(Default initial capacity).
  list.ensureCapacity(20); // Now it can hold 20 elements.

  list.trimTosize();

如何在 Java 中同步 ArrayList

什么是 Java 中的同步?

从技术上讲,java 中的同步是一次只允许一个线程完全完成任务的过程。它只允许一个线程访问单个资源或单个任务。

当多个线程同时访问相同的资源时,程序可能会产生不是期望值的输出。因此,可以使用称为同步的技术来解决此问题。同步的目的是控制对共享资源的访问。

我们知道默认情况下 ArrayList 类不是线程安全。这意味着多个线程可以同时访问同一个 ArrayList 对象或实例。

因此,如果没有显式同步,它不能在多线程环境中被正确地使用。这是因为如果在多线程环境中使用 ArrayList 而不使用同步技术,那么它可能会产生不可预测的输出。

程序源代码 5:

代码语言:javascript代码运行次数:0运行复制
package arrayListProgram; 
import java.util.ArrayList;
public class MultiThreadEx extends Thread 
{ 
// Declare ArrayList variable. 
   ArrayList<Integer> list; 

// Create a one parameter constructor with parameter 'list' and type ArrayList. 
   MultiThreadEx(ArrayList<Integer> list)
   { 
     this.list = list; 
   } 
@Override 
public void run()
{ 
  System.out.println("Run method"); 
  for(int i = 0 ; i < = 6; i++)
  { 
// Adding elements in the list. 
   list.add(i); 
   try { 
// Call sleep() method to delay some time. 
     Thread.sleep(50); 
   }
   catch(InterruptedException e)
   { 
     e.printStackTrace(); 
   } 
  } 
} 
public static void main(String[] args) 
{ 
// Creates an ArrayList object with an initial capacity of 10. 
   ArrayList<Ineger> list = new ArrayList<Integer>(); 

// Create multiple thread class objects m1, m2 and passes 'list' as a parameter. 
   MultiThreadEx m1 = new MultiThreadEx(list); 
   MultiThreadEx m2 = new MultiThreadEx(list); 

// Call start() method to start thread using m1 and m2 reference variable. 
    m1.start(); 
    m2.start(); 
   try { 
// Call join() method to complete the task of adding elements in the ArrayList. 
     m1.join(); 
     m2.join(); 
   } 
   catch (InterruptedException e) 
   { 
      e.printStackTrace(); 
    } 
Integer sizelist = list.size(); 
System.out.println("Size of list is " + sizelist); 
for(Integer i : list)
{ 
 System.out.println("num - " + i); 
} 
 } 
}
代码语言:javascript代码运行次数:0运行复制
Output: 
       Run method 
       Run method 
       Size of list is 12 
       num - 0 
       num - 0 
       num - 1 
       num - 2 
       num - 2 
       num - 3 
       num - 3 
       num - 4 
       num - 4 
       num - 5 
       num - 5 
       num - 6

解释:

正如您在前面的示例程序中观察到的那样,ArrayList 实例在类对象 m1 和 m2 的两个线程之间共享。每个线程都尝试在 ArrayList 中添加 6 个元素。由于数组列表未同步。

因此,预期的输出是不可预测的。当我们运行上面的代码时,它显示 ArrayList 的大小是 12(而不是 14)。元素 1 和 6 在列表中仅插入一次。

让我们看看上面的程序发生了什么。

➤ 从主线程创建线程 1 时,它会在列表中插入元素 0。在列表中添加元素 0 后,线程 1 进入睡眠位置。

由于我们使用join()方法完成通过m1将元素从0添加到6的任务,所以当thread-1进入睡眠状态时,同时,主线程将启动thread-2执行,并将在列表中添加一个元素0。

➤ 当线程 1 的休眠时间结束时,线程 1 将再次进入运行状态,并在列表中添加元素 1。添加后,它将再次进入睡眠位置。

➤ 休眠时间结束后,它再次进入运行状态以插入元素 2。添加后,线程 1 将再次进入睡眠状态。同时,主线程将再次启动线程 2 以完成其任务并添加不可预测的元素 2。

正如您在程序中观察到的那样,在多线程环境中使用 ArrayList 并不能提供线程安全性。这是因为 ArrayList 未同步。

那么,我们将如何在Java中获得具有线程安全性的同步ArrayList呢?

有两种方法可以获取 ArrayList 的同步版本。它们如下:

  1. 通过使用 Collections.syncdList() 方法
  2. 通过使用 CopyOnWriteArrayList
使用 Collections.syncdList() 方法同步 ArrayList

此方法用于同步 Java 中的集合。此方法的语法如下:

语法:

代码语言:javascript代码运行次数:0运行复制
public static List<T> synchronizedList(List<T> list)

1. syncdList() 方法接受 List,它可以是 List 接口的实现。例如,ArrayList 和 LinkedList。 2. 此方法的返回类型是同步列表(线程安全)。

3. 同步列表是方法的名称。

4. 参数列表是要包装在同步列表中的列表。

5. T 表示泛型的类型。

注意:迭代器在同步块中用于同步,以避免 Java 中的 ConcurrentModificationException。同步的 ArrayList 返回的迭代器是快速故障的。当在迭代期间列表中发生任何修改时,它将抛出 ConcurrentModificationException。

让我们举一个基本的例子来同步 java 中的 ArrayList。

代码语言:javascript代码运行次数:0运行复制
ArrayList<String> al = new ArrayList<String>(); // Non-synchronized.
 List l = Collections.synchronizedList( al );
        l ➟  synchronized.
        al ➟ Non-synchronized.
or, 
 List<String> synlist = Collections.synchronizedList( new ArrayList<String>);

同样,我们可以使用以下语法获取 Set, Map 对象的同步版本:

代码语言:javascript代码运行次数:0运行复制
public static Set synchronizedList( Set s );
public static Map synchronizedList( Map m );

让我们举一个示例程序,其中我们将同步未同步的 ArrayList 对象列表,然后我们将调用 iterator() 方法来迭代同步的 ArrayList 对象列表。

程序源代码 1:

代码语言:javascript代码运行次数:0运行复制
package synchronizeTest; 
import java.util.ArrayList; 
import java.util.Collections; 
import java.util.Iterator; 
import java.util.List; 

public class ArrayListSynchronizationTest 
{ 
public static void main(String[] args) 
{ 
// Create an ArrayList object with initial capacity of 10. 
// Non-synchronized ArrayList Object. 
   List<String> l = new ArrayList<String>(); 

// Add elements in the list. 
    l.add("Apple"); 
    l.add("Orange"); 
    l.add("Banana"); 
    l.add("Pineapple"); 
    l.add("Guava"); 

// Synchronizing ArrayList in Java. 
   List<String> synlist = Collections.synchronizedList( l ); // l is non-synchronized. 

// Here, we will use a synchronized block to avoid the non-deterministic behavior. 
   synchronized(synlist) 
   { 
// Call iterator() method to iterate the ArrayList. 
    Iterator<String> itr = synlist.iterator(); 
    while(itr.hasNext())
    { 
      String str = itr.next(); 
      System.out.println(str); 
    } 
  } 
 } 
}
代码语言:javascript代码运行次数:0运行复制
Output: 
       Apple Orange Banana Pineapple Guava

在前面的程序中,ArrayList 通过调用将整个列表锁定到同步块中的 syncdList() 方法来实现线程安全。 让我们以另一个程序为例,我们将通过在迭代期间向同步列表中添加一个数字来检查 ConcurrentModificationException 的出现。

程序源代码 2:

代码语言:javascript代码运行次数:0运行复制
package synchronizeTest; 
import java.util.ArrayList; 
import java.util.Collections; 
import java.util.Iterator; 
import java.util.List; 
public class CMETest 
{ 
public static void main(String[] args) 
{ 
  ArrayList<Integer> al = new ArrayList<Integer>(); 
  for(int i = 0; i < 10; i++) 
  { 
    al.add(i); 
  } 
 List<Integer> synlist = Collections.synchronizedList(al); 
  synchronized(synlist) 
  { 
    Iterator<Integer> itr = synlist.iterator(); 
    while(itr.hasNext()) 
    { 
      al.add(20); // It will throw ConcurrentModificationException because we cannot modify list during Iteration. 
      System.out.println(itr.next()); 
    } 
   } 
 }
}
代码语言:javascript代码运行次数:0运行复制
Output: 
       Exception in thread "main" java.util.ConcurrentModificationException
在 Java 中使用 CopyOnWriteArrayList 类同步 ArrayList

1. CopyOnWriteArrayList 实现了 List 接口并创建一个空列表。

2.它按指定集合的顺序创建元素列表。

3. 是数组列表的线程安全并发访问。修改 ArrayList 时,它将创建底层数组的新副本。

4. CopyOnWriteArrayList 返回的 Iterator 和 ListIterator 是完全线程安全的。 当 ArrayList 在迭代过程中被修改时,它不会抛出 ConcurrentModificationException。

5. CopyOnWriteArrayList 不会锁定整个列表。当线程写入列表时,它只是将列表替换为底层数组的新副本。

通过这种方式,它为多个线程提供了 ArrayList 的并发访问,而不会锁定。由于读取操作是线程安全的,因此两个线程不能同时写入列表。

创建 CopyOnWriteArrayList 对象的语法如下:

语法:

代码语言:javascript代码运行次数:0运行复制
CopyOnWriteArrayList<T> al = new CopyOnWriteArrayList<T>(); // T is generic.

让我们创建一个程序,我们将使用 CopyOnWriteArrayList 类同步 ArrayList 中的元素列表。

程序源代码 3:

代码语言:javascript代码运行次数:0运行复制
package synchronizeTest; 
import java.util.Iterator; 
import java.util.concurrent.CopyOnWriteArrayList; 
public class SynArrayListUsingCOWA 
{ 
public static void main(String[] args) 
{ 
// Create a thread-safe ArrayList. 
   CopyOnWriteArrayList<String> al = new CopyOnWriteArrayList<String>(); 
    al.add("Pen"); 
    al.add("Pencil"); 
    al.add("Copy"); 
    al.add("Eraser"); 
    al.add("Shapner"); 
   System.out.println("Displaying synchronized ArrayList "); 

// Synchronized block is not required in this method. 
   Iterator<String> itr = al.iterator(); 
   while(itr.hasNext()) 
   {  
     String str = itr.next(); 
     System.out.println(str); 
   } 
  } 
 }
代码语言:javascript代码运行次数:0运行复制
Output: 
       Displaying synchronized ArrayList 
       Pen Pencil Copy Eraser Shapner

让我们制作另一个程序,我们将尝试在迭代期间在同步列表中添加一个元素。在这里,我们将检查 CopyOnWriteArrayList 是否会在迭代期间抛出 ConcurrentModificationException。

程序源代码 4:

代码语言:javascript代码运行次数:0运行复制
package synchronizeTest; 
import java.util.Collections; 
import java.util.Iterator; 
import java.util.List; 
import java.util.concurrent.CopyOnWriteArrayList; 

public class AddingTest 
{ 
public static void main(String[] args) 
{ 
 CopyOnWriteArrayList<String> al = new CopyOnWriteArrayList<String>(); 
   al.add("A"); 
   al.add("B"); 
   al.add(null); 
   al.add("D"); 
   al.add("E"); 
   al.add("H"); 
 System.out.println(al); 
 List<String> synlist = Collections.synchronizedList(al); 

// Here, Synchronized block is not required. 
// Call iterator() method using reference variable synlist. 
   Iterator<String> itr = synlist.iterator(); 
   while(itr.hasNext()) 
   { 
     al.set(5, "F"); // It will not throw ConcurrentModificationException during Iteration. 
     String str = itr.next(); 
     System.out.println(str); 
    } 
   System.out.println(al); 
  } 
 }
代码语言:javascript代码运行次数:0运行复制
Output: 
       [A, B, null, D, E, H] 
       A B null D E H 
       [A, B, null, D, E, F]

正如您在上面的程序中观察到的那样,在迭代过程中,我们可以使用 CopyOnWriteArrayList 方法轻松地在同步列表中添加一个元素。


ArrayList 可以在以下情况中使用

  • 我们想存储重复的元素。
  • 我们想要存储空元素。
  • 在 Java 中,我们使用时添加和删除元素类操作比较少,需要执行大量检索性任务。
  • 我们尽量不在Java的多线程环境中使用它,因为ArrayList不是线程同步的。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。 原始发表:2008-11-15,如有侵权请联系 cloudcommunity@tencent 删除arraylist对象数组同步java

发布者:admin,转转请注明出处:http://www.yc00.com/web/1747966876a4712372.html

相关推荐

  • ArrayList全面使用

    Java 中的 ArrayList 是一个可调整大小的数组,可以在内存中增长或收缩。它是使用初始容量动态创建的。这意味着如果超过数组的初始容量,将自动创建一个容量更大的新数组,并将当前数组中的所有元素复制到新数组中。数组列表中的元素是从零索

    8小时前
    20

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信