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的类,包含主方法。这是程序的入口点。
-
步骤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
Java 5中一个受欢迎的集合类,可帮助实现生产者-消费者设计模式的是BlockingQueue。它使用简单,并且在put()和take()函数中内置了阻塞支持。
如果队列已满,put()方法将等待;如果队列为空,take()方法将等待。因此,更容易控制生产者和消费者之间的物料移动。
ArrayBlockingQueue和LinkedBlockingQueue是Java 5中可用的两个不同版本的BlockingQueue。它们都使用先进先出(FIFO)的元素排列方式。LinkedBlockingQueue可能是有界的,而ArrayBlockingQueue是有界的,并且由数组支持。
CopyOnWriteArrayList
CopyOnWriteArrayList是一种数据结构,每次有更新操作时,它都会创建底层ArrayList的克隆副本。这个克隆副本会被JVM自动与原始ArrayList同步。因此,执行读操作的线程不受影响。
然而,这种方法可能会很昂贵,因为每次更新操作都会创建一个克隆副本。因此,如果频繁操作是读操作,CopyOnWriteArrayList是最好的选择。这个数据结构是ArrayList的线程安全版本,允许插入重复项、空值和异类对象,并保持它们的顺序。
关于CopyOnWriteArrayList需要注意的一个重要事项是,它的Iterator不能执行删除操作,调用迭代器的add()和set()方法会导致UnsupportedOperationException运行时异常。此外,CopyOnWriteArrayList的Iterator永远不会抛出ConcurrentModificationException。
步骤
- 步骤1 - 程序将三个组件添加到属于CopyOnWriteArrayList类的对象”l”中。即使主线程继续遍历列表,仍会启动一个新线程将一个新的元素添加到其中。
-
步骤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应用程序的性能。