Java 中并发集合的必要性
Java 中的并发集合
Java 是一种众所周知的计算机语言,它支持并发和多线程。开发人员可以使用同步关键字来保证线程之间的正确同步。此外,Java 的集合框架还提供各种可用于保存和操作数据的集合。
开发人员可以使用 synchronized 关键字使这些集合线程安全。在涉及多个线程并发执行的程序中,高效且安全地执行程序取决于此功能。
Java 中并发集合的必要性是什么?
ArrayList、LinkedList、HashSet、HashMap 和 LinkedHashMap 只是 Java 集合框架中的一些类,它们并非旨在在多线程环境中安全使用。
这意味着如果我们在多个线程并发访问这些集合的情况下使用它们,则结果需要更加准确。我们需要线程安全的类,多个线程可以访问这些类而不会导致任何问题来解决此问题。
虽然我们可以使用 Collections.synchronizedList(list) 等方法同步这些集合,但这并不是最佳解决方案。
即使其他线程只需要读取数据,当我们使用此方法时,一次只有一个线程可以访问整个列表。这可能会导致机制效率降低。我们必须使用并发集合来更有效地管理并发访问。这些集合是创建的,以便多个线程可以同时访问它们而不会出现问题。
ConcurrentHashMap
ConcurrentHashMap 是 Java 5 中广泛使用的集合类。它之所以受欢迎,是因为它为 Hashtable 或 Synchronized Map 类提供了并发选项,通过使用细粒度锁定,可以实现更高的并发性。
使用 ConcurrentHashMap,许多读取器可以同时访问 Map,而 Map 的一部分会被锁定以进行写操作,具体取决于 Map 的并发级别。这有助于提供比同步映射更好的可扩展性。
算法
步骤 1 - 导入 java.util.concurrent.* 包。这包含并发实用程序的类。
步骤 2 - 定义一个名为 MyConcurrentHashMap 的类,其中包含 main 方法。这是程序的入口点。
步骤 3 - 创建一个名为 concurrentHashMap 的 ConcurrentHashMap 类的实例。
步骤 4 - 使用 put 方法向 concurrentHashMap 添加三个键值对。每个键值对表示产品 ID 及其对应的产品名称。
步骤 5 - 使用 println 方法将 concurrentHashMap 的内容打印到控制台。这将以无序的方式输出 concurrentHashMap 的内容。
示例 1
此程序演示了如何在 Java 中使用 ConcurrentHashMap 类。
import java.util.concurrent.*;
public class MyConcurrentHashMap {
public static void main(String[] args){
ConcurrentHashMap<String, String> concurrentHashMap
= new ConcurrentHashMap<>();
concurrentHashMap.put("P001", "Apple Iphone");
concurrentHashMap.put("P002", "Samsung Smartphone");
concurrentHashMap.put("P003", "Google Pixel");
System.out.println(concurrentHashMap);
}
}
输出
{P001=Apple Iphone, P003=Google Pixel, P002=Samsung Smartphone}
BlockingQueue
BlockingQueue 是 Java 5 中一个流行的集合类,它有助于实现生产者-消费者设计模式。它易于使用,并且为 put() 和 take() 函数内置了阻塞支持。
如果队列已满,put() 方法将等待;如果队列为空,take() 方法将等待。因此,它可以更轻松地控制生产者和消费者之间材料的移动。
ArrayBlockingQueue 和 LinkedBlockingQueue 是 Java 5 中提供的 BlockingQueue 的两个不同版本。它们都使用先进先出 (FIFO) 元素排列。ArrayBlockingQueue 是有界的,并由数组支持,而 LinkedBlockingQueue 可能是无界的。
CopyOnWriteArrayList
CopyOnWriteArrayList 是一种数据结构,每次进行更新操作时都会创建底层 ArrayList 的克隆副本。JVM 会自动将此克隆副本与原始 ArrayList 同步。因此,执行读取操作的线程不受影响。
但是,这种方法可能代价高昂,因为每次更新操作都会创建克隆副本。因此,如果频繁的操作是读取操作,则 CopyOnWriteArrayList 是最佳选择。此数据结构是 ArrayList 的线程安全版本,允许插入重复项、空值和异构对象,同时保留其顺序。
关于 CopyOnWriteArrayList 需要注意的一点是,它的迭代器无法执行删除操作,并且在迭代器上调用 add() 和 set() 方法会导致 UnsupportedOperationException 运行时异常。此外,CopyOnWriteArrayList 的迭代器永远不会抛出 ConcurrentModificationException。
算法
步骤 1 - 程序将三个组件添加到名为“l”的对象中,该对象属于 CopyOnWriteArrayList 类。即使主线程继续循环遍历列表,也会启动一个新线程向其中追加一个新元素。
步骤 2 - 为了保护迭代过程不受子线程可能对列表进行的任何更改的影响,软件依赖于 CopyOnWriteArrayList 类。
步骤 3 - 在打印列表中的每个元素(包括子线程添加的“Z”元素)后,会按顺序打印整个列表。
示例 2
下面的程序演示了如何使用 CopyOnWriteArrayList 类来确保在迭代列表时线程安全。
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
public class ConcurrentDemo extends Thread {
static CopyOnWriteArrayList<String> l
= new CopyOnWriteArrayList<String>();
public void run(){
// Child thread trying to
// add new element in the
// Collection object
l.add("Z");
}
public static void main(String[] args)
throws InterruptedException{
l.add("W");
l.add("X");
l.add("Y");
// We create a child thread
// that is going to modify
// ArrayList l.
ConcurrentDemo t = new ConcurrentDemo();
t.start();
Thread.sleep(1000);
// Now we iterate through
// the ArrayList and get
// exception.
Iterator itr = l.iterator();
while (itr.hasNext()) {
String s = (String)itr.next();
System.out.println(s);
Thread.sleep(1000);
}
System.out.println(l);
}
}
输出
W X Y Z [W, X, Y, Z]
结论
在 Java 中使用多个线程与集合一起使用时,使用线程安全的集合(如 ConcurrentHashMap、BlockingQueue 和 CopyOnWriteArrayList)对于避免数据不一致性和提高程序效率至关重要。这些集合提供了各种功能以满足不同的并发需求,并且可以提高涉及多线程的 Java 应用程序的性能。
数据结构
网络
关系数据库管理系统
操作系统
Java
iOS
HTML
CSS
Android
Python
C 编程
C++
C#
MongoDB
MySQL
Javascript
PHP