Java ArrayList同步化

Java ArrayList同步化

ArrayList的实现在默认情况下是不同步的。这意味着如果一个线程在结构上修改它,并且多个线程同时访问它,它必须在外部进行同步。结构上的修改意味着从列表中增加或删除元素,或者明确地调整后备数组的大小。改变现有元素的值不属于结构性修改。

有两种方法可以创建一个同步ArrayList

1.Collections.synchronizedList()方法。
2.使用CopyOnWriteArrayList。

方法一:使用 Collections.synchronizedList() 方法

为了进行串行访问,对后备列表的所有访问都必须通过返回的列表来完成。当用户在返回的列表上进行迭代时,必须对其进行 手动 同步。

public static  List <T> synchronizedList(List<T> list)
  • 接受一个List,它可以是 List 接口的实现,例如ArrayList, LinkedList。
  • 返回一个由指定列表支持的同步(线程安全)列表。
  • 参数list是要被包装成同步列表的列表。
  • T代表通用
// Java program to demonstrate working of
// Collections.synchronizedList
 
import java.util.*;
 
class GFG
{
    public static void main (String[] args)
    {
        List<String> list =
           Collections.synchronizedList(new ArrayList<String>());
 
        list.add("practice");
        list.add("code");
        list.add("quiz");
 
        synchronized(list)
        {
            // must be in synchronized block
            Iterator it = list.iterator();
 
            while (it.hasNext())
                System.out.println(it.next());
        }
    }
}

输出

practice
code
quiz

方法2:使用CopyOnWriteArrayList

CopyOnWriteArrayList<T> threadSafeList = new CopyOnWriteArrayList<T>();
  • 创建一个空的List。
  • 它实现了 List 接口。
  • 它是ArrayList的一个线程安全的变体。
  • T代表通用

ArrayList的线程安全变体,其中所有的变异操作(例如,添加、设置、删除……)都是通过创建一个底层 数组 的单独副本来实现的 。 它通过创建一个单独的List副本来实现线程安全,这与向量或其他用于提供线程安全的集合不同。

  • 当你不能或不想 同步 遍历,但又需要防止并发线程之间的干扰时,它就很有用。
  • 它的 成本很高 ,因为它涉及到每个写操作的单独的 数组拷贝 (例如,添加、设置、删除。
  • 当你有 List ,需要遍历它的元素并且不经常修改它时,它是非常有效的。

即使copyOnWriteArrayList在迭代器创建后被修改,该迭代器也不会抛出 ConcurrentModificationException 。迭代器在ArrayList的单独副本上进行迭代,同时在ArrayList的另一个副本上进行写操作。

// Java program to illustrate the thread-safe ArrayList.
 
import java.io.*;
import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList;
 
class GFG
{
    public static void main (String[] args)
    {
        // creating a thread-safe Arraylist.
        CopyOnWriteArrayList<String> threadSafeList
            = new CopyOnWriteArrayList<String>();
 
        // Adding elements to synchronized ArrayList
        threadSafeList.add("geek");
        threadSafeList.add("code");
        threadSafeList.add("practice");
 
        System.out.println("Elements of synchronized ArrayList :");
 
        // Iterating on the synchronized ArrayList using iterator.
        Iterator<String> it = threadSafeList.iterator();
 
        while (it.hasNext())
            System.out.println(it.next());
    }
}

输出

Elements of synchronized ArrayList :
geek
code
practice

如果我们试图通过 迭代器的方法修改CopyOnWriteArrayList会发生什么

如果你试图通过迭代器自己的方法(例如add(), set(), remove())来修改 CopyOnWriteArrayList ,它会抛出UnsupportedOperationException。

// Java program to illustrate the thread-safe ArrayList
 
import java.io.*;
import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList;
 
class GFG
{
    public static void main (String[] args)
    {
        // creating a thread-safe Arraylist.
        CopyOnWriteArrayList<String> threadSafeList =
            new CopyOnWriteArrayList<String>();
 
        // Adding elements to synchronized ArrayList
        threadSafeList.add("geek");
        threadSafeList.add("code");
        threadSafeList.add("practice");
 
        System.out.println("Elements of synchronized ArrayList :");
 
        // Iterating on the synchronized ArrayList using iterator.
        Iterator<String> it = threadSafeList.iterator();
 
        while (it.hasNext())
        {
            String str = it.next();
            it.remove();
        }
    }
}

运行时错误

Exception in thread "main" java.lang.UnsupportedOperationException
    at java.util.concurrent.CopyOnWriteArrayList$COWIterator.remove
        (CopyOnWriteArrayList.java:1176)
    at GFG.main(File.java:28)

CopyOnWriteArrayList的其他构造函数

  1. **CopyOnWriteArrayList(Collection <? extends E> c) **: 创建一个包含指定集合元素的列表,其顺序是由集合的迭代器返回。

  2. CopyOnWriteArrayList(E[] toCopyIn) : 创建一个包含给定数组副本的列表。

当向量是同步的,为什么使用ArrayList

  1. 性能: Vector是 同步的 和线程安全的,正因为如此,它比ArrayList稍慢。
  2. 功能: Vector在每个单独的操作层面上进行同步。一般来说,程序员喜欢对整个操作序列进行同步。同步单个操作既不安全也比较慢。
  3. 矢量过时: 矢量被认为是过时的,在java中被非官方地废弃。而且,向量在每个单独的操作上都要进行同步,这几乎是不可能的。大多数java程序员喜欢使用ArrayList,因为如果他们需要同步,他们可能会明确地同步arrayList。

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程