To choose which list you need you to use requires some basic understanding of each of the implementations.
Summary
Implementation | Underlying Structure | Thread-Safe? | Remarks |
---|---|---|---|
ArrayList | Dynamic Array | No | General-purpose, random access. |
LinkedList | Doubly Linked List | No | Frequent insertions/deletions. Slower access (O(n)). |
CopyOnWriteArrayList | Dynamic Array | Yes | Thread-safe, read-heavy workloads. |
List.of() / Immutable | Fixed Array | Yes | Unmodifiable data. |
When to Use Which?
- ArrayList: Default choice for most cases.
- LinkedList: Frequent insertions/deletions at both ends (e.g., queues).
- CopyOnWriteArrayList: Thread-safe reads with infrequent writes.
- Immutable Lists (List.of()): Data that never changes.
Thread-Safe Demo
Here is examples to see how ArrayList is not thread safe
<span>package</span> <span>org.example</span><span>;</span><span>import</span> <span>java.util.ArrayList</span><span>;</span><span>import</span> <span>java.util.List</span><span>;</span><span>public</span> <span>class</span> <span>ArrayListThreadSafetyDemo</span> <span>{</span><span>public</span> <span>static</span> <span>void</span> <span>main</span><span>(</span><span>String</span><span>[]</span> <span>args</span><span>)</span> <span>throws</span> <span>InterruptedException</span> <span>{</span><span>List</span><span><</span><span>Integer</span><span>></span> <span>unsafeList</span> <span>=</span> <span>new</span> <span>ArrayList</span><span><>();</span><span>// Create two threads that add elements to the same list</span><span>Thread</span> <span>thread1</span> <span>=</span> <span>new</span> <span>Thread</span><span>(()</span> <span>-></span> <span>addElements</span><span>(</span><span>unsafeList</span><span>));</span><span>Thread</span> <span>thread2</span> <span>=</span> <span>new</span> <span>Thread</span><span>(()</span> <span>-></span> <span>addElements</span><span>(</span><span>unsafeList</span><span>));</span><span>thread1</span><span>.</span><span>start</span><span>();</span><span>thread2</span><span>.</span><span>start</span><span>();</span><span>// Wait for both threads to finish</span><span>thread1</span><span>.</span><span>join</span><span>();</span><span>thread2</span><span>.</span><span>join</span><span>();</span><span>// Expected size: 2000 (1000 elements per thread)</span><span>// The size is often less than 2000, and the program may occasionally throw exceptions like ArrayIndexOutOfBoundsException.</span><span>/* Race Condition: Two threads might both try to increment the size field and write to the same array index, causing one write to be overwritten. Internal Array Corruption: The internal elementData array might resize inconsistently, leading to index errors. Lost Updates: The size counter may not update atomically, resulting in fewer elements than expected. */</span><span>System</span><span>.</span><span>out</span><span>.</span><span>println</span><span>(</span><span>"Final list size: "</span> <span>+</span> <span>unsafeList</span><span>.</span><span>size</span><span>());</span><span>}</span><span>private</span> <span>static</span> <span>void</span> <span>addElements</span><span>(</span><span>List</span><span><</span><span>Integer</span><span>></span> <span>list</span><span>)</span> <span>{</span><span>for</span> <span>(</span><span>int</span> <span>i</span> <span>=</span> <span>0</span><span>;</span> <span>i</span> <span><</span> <span>1000</span><span>;</span> <span>i</span><span>++)</span> <span>{</span><span>list</span><span>.</span><span>add</span><span>(</span><span>i</span><span>);</span> <span>// Concurrent modification</span><span>}</span><span>}</span><span>}</span><span>package</span> <span>org.example</span><span>;</span> <span>import</span> <span>java.util.ArrayList</span><span>;</span> <span>import</span> <span>java.util.List</span><span>;</span> <span>public</span> <span>class</span> <span>ArrayListThreadSafetyDemo</span> <span>{</span> <span>public</span> <span>static</span> <span>void</span> <span>main</span><span>(</span><span>String</span><span>[]</span> <span>args</span><span>)</span> <span>throws</span> <span>InterruptedException</span> <span>{</span> <span>List</span><span><</span><span>Integer</span><span>></span> <span>unsafeList</span> <span>=</span> <span>new</span> <span>ArrayList</span><span><>();</span> <span>// Create two threads that add elements to the same list</span> <span>Thread</span> <span>thread1</span> <span>=</span> <span>new</span> <span>Thread</span><span>(()</span> <span>-></span> <span>addElements</span><span>(</span><span>unsafeList</span><span>));</span> <span>Thread</span> <span>thread2</span> <span>=</span> <span>new</span> <span>Thread</span><span>(()</span> <span>-></span> <span>addElements</span><span>(</span><span>unsafeList</span><span>));</span> <span>thread1</span><span>.</span><span>start</span><span>();</span> <span>thread2</span><span>.</span><span>start</span><span>();</span> <span>// Wait for both threads to finish</span> <span>thread1</span><span>.</span><span>join</span><span>();</span> <span>thread2</span><span>.</span><span>join</span><span>();</span> <span>// Expected size: 2000 (1000 elements per thread)</span> <span>// The size is often less than 2000, and the program may occasionally throw exceptions like ArrayIndexOutOfBoundsException.</span> <span>/* Race Condition: Two threads might both try to increment the size field and write to the same array index, causing one write to be overwritten. Internal Array Corruption: The internal elementData array might resize inconsistently, leading to index errors. Lost Updates: The size counter may not update atomically, resulting in fewer elements than expected. */</span> <span>System</span><span>.</span><span>out</span><span>.</span><span>println</span><span>(</span><span>"Final list size: "</span> <span>+</span> <span>unsafeList</span><span>.</span><span>size</span><span>());</span> <span>}</span> <span>private</span> <span>static</span> <span>void</span> <span>addElements</span><span>(</span><span>List</span><span><</span><span>Integer</span><span>></span> <span>list</span><span>)</span> <span>{</span> <span>for</span> <span>(</span><span>int</span> <span>i</span> <span>=</span> <span>0</span><span>;</span> <span>i</span> <span><</span> <span>1000</span><span>;</span> <span>i</span><span>++)</span> <span>{</span> <span>list</span><span>.</span><span>add</span><span>(</span><span>i</span><span>);</span> <span>// Concurrent modification</span> <span>}</span> <span>}</span> <span>}</span>package org.example; import java.util.ArrayList; import java.util.List; public class ArrayListThreadSafetyDemo { public static void main(String[] args) throws InterruptedException { List<Integer> unsafeList = new ArrayList<>(); // Create two threads that add elements to the same list Thread thread1 = new Thread(() -> addElements(unsafeList)); Thread thread2 = new Thread(() -> addElements(unsafeList)); thread1.start(); thread2.start(); // Wait for both threads to finish thread1.join(); thread2.join(); // Expected size: 2000 (1000 elements per thread) // The size is often less than 2000, and the program may occasionally throw exceptions like ArrayIndexOutOfBoundsException. /* Race Condition: Two threads might both try to increment the size field and write to the same array index, causing one write to be overwritten. Internal Array Corruption: The internal elementData array might resize inconsistently, leading to index errors. Lost Updates: The size counter may not update atomically, resulting in fewer elements than expected. */ System.out.println("Final list size: " + unsafeList.size()); } private static void addElements(List<Integer> list) { for (int i = 0; i < 1000; i++) { list.add(i); // Concurrent modification } } }
Enter fullscreen mode Exit fullscreen mode
To have a thread safe list, choose CopyOnWriteArrayList
instead. Since it is coming from same List
interface, most methods are the same.
<span>package</span> <span>org.example</span><span>;</span><span>import</span> <span>java.util.List</span><span>;</span><span>import</span> <span>java.util.concurrent.CopyOnWriteArrayList</span><span>;</span><span>public</span> <span>class</span> <span>CopyOnWriteArrayListThreadSafetyDemo</span> <span>{</span><span>public</span> <span>static</span> <span>void</span> <span>main</span><span>(</span><span>String</span><span>[]</span> <span>args</span><span>)</span> <span>throws</span> <span>InterruptedException</span> <span>{</span><span>List</span><span><</span><span>Integer</span><span>></span> <span>unsafeList</span> <span>=</span> <span>new</span> <span>CopyOnWriteArrayList</span><span><>();</span><span>// Create two threads that add elements to the same list</span><span>Thread</span> <span>thread1</span> <span>=</span> <span>new</span> <span>Thread</span><span>(()</span> <span>-></span> <span>addElements</span><span>(</span><span>unsafeList</span><span>));</span><span>Thread</span> <span>thread2</span> <span>=</span> <span>new</span> <span>Thread</span><span>(()</span> <span>-></span> <span>addElements</span><span>(</span><span>unsafeList</span><span>));</span><span>thread1</span><span>.</span><span>start</span><span>();</span><span>thread2</span><span>.</span><span>start</span><span>();</span><span>// Wait for both threads to finish</span><span>thread1</span><span>.</span><span>join</span><span>();</span><span>thread2</span><span>.</span><span>join</span><span>();</span><span>// Expected size: 2000 (1000 elements per thread)</span><span>System</span><span>.</span><span>out</span><span>.</span><span>println</span><span>(</span><span>"Final list size: "</span> <span>+</span> <span>unsafeList</span><span>.</span><span>size</span><span>());</span><span>}</span><span>private</span> <span>static</span> <span>void</span> <span>addElements</span><span>(</span><span>List</span><span><</span><span>Integer</span><span>></span> <span>list</span><span>)</span> <span>{</span><span>for</span> <span>(</span><span>int</span> <span>i</span> <span>=</span> <span>0</span><span>;</span> <span>i</span> <span><</span> <span>1000</span><span>;</span> <span>i</span><span>++)</span> <span>{</span><span>list</span><span>.</span><span>add</span><span>(</span><span>i</span><span>);</span> <span>// Concurrent modification</span><span>}</span><span>}</span><span>}</span><span>package</span> <span>org.example</span><span>;</span> <span>import</span> <span>java.util.List</span><span>;</span> <span>import</span> <span>java.util.concurrent.CopyOnWriteArrayList</span><span>;</span> <span>public</span> <span>class</span> <span>CopyOnWriteArrayListThreadSafetyDemo</span> <span>{</span> <span>public</span> <span>static</span> <span>void</span> <span>main</span><span>(</span><span>String</span><span>[]</span> <span>args</span><span>)</span> <span>throws</span> <span>InterruptedException</span> <span>{</span> <span>List</span><span><</span><span>Integer</span><span>></span> <span>unsafeList</span> <span>=</span> <span>new</span> <span>CopyOnWriteArrayList</span><span><>();</span> <span>// Create two threads that add elements to the same list</span> <span>Thread</span> <span>thread1</span> <span>=</span> <span>new</span> <span>Thread</span><span>(()</span> <span>-></span> <span>addElements</span><span>(</span><span>unsafeList</span><span>));</span> <span>Thread</span> <span>thread2</span> <span>=</span> <span>new</span> <span>Thread</span><span>(()</span> <span>-></span> <span>addElements</span><span>(</span><span>unsafeList</span><span>));</span> <span>thread1</span><span>.</span><span>start</span><span>();</span> <span>thread2</span><span>.</span><span>start</span><span>();</span> <span>// Wait for both threads to finish</span> <span>thread1</span><span>.</span><span>join</span><span>();</span> <span>thread2</span><span>.</span><span>join</span><span>();</span> <span>// Expected size: 2000 (1000 elements per thread)</span> <span>System</span><span>.</span><span>out</span><span>.</span><span>println</span><span>(</span><span>"Final list size: "</span> <span>+</span> <span>unsafeList</span><span>.</span><span>size</span><span>());</span> <span>}</span> <span>private</span> <span>static</span> <span>void</span> <span>addElements</span><span>(</span><span>List</span><span><</span><span>Integer</span><span>></span> <span>list</span><span>)</span> <span>{</span> <span>for</span> <span>(</span><span>int</span> <span>i</span> <span>=</span> <span>0</span><span>;</span> <span>i</span> <span><</span> <span>1000</span><span>;</span> <span>i</span><span>++)</span> <span>{</span> <span>list</span><span>.</span><span>add</span><span>(</span><span>i</span><span>);</span> <span>// Concurrent modification</span> <span>}</span> <span>}</span> <span>}</span>package org.example; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; public class CopyOnWriteArrayListThreadSafetyDemo { public static void main(String[] args) throws InterruptedException { List<Integer> unsafeList = new CopyOnWriteArrayList<>(); // Create two threads that add elements to the same list Thread thread1 = new Thread(() -> addElements(unsafeList)); Thread thread2 = new Thread(() -> addElements(unsafeList)); thread1.start(); thread2.start(); // Wait for both threads to finish thread1.join(); thread2.join(); // Expected size: 2000 (1000 elements per thread) System.out.println("Final list size: " + unsafeList.size()); } private static void addElements(List<Integer> list) { for (int i = 0; i < 1000; i++) { list.add(i); // Concurrent modification } } }
Enter fullscreen mode Exit fullscreen mode
You can also use to have a thread-safe list.
<span>List</span><span><</span><span>Integer</span><span>></span> <span>safeList</span> <span>=</span> <span>Collections</span><span>.</span><span>synchronizedList</span><span>(</span><span>new</span> <span>ArrayList</span><span><>());</span><span>List</span><span><</span><span>Integer</span><span>></span> <span>safeList</span> <span>=</span> <span>Collections</span><span>.</span><span>synchronizedList</span><span>(</span><span>new</span> <span>ArrayList</span><span><>());</span>List<Integer> safeList = Collections.synchronizedList(new ArrayList<>());
Enter fullscreen mode Exit fullscreen mode
原文链接:Choosing List Implementation in Java: ArrayList, LinkedList, CopyOnWriteArrayList, List.Of
© 版权声明
THE END
暂无评论内容