并发集合(三)使用阻塞线程安全的列表

简介:

使用阻塞线程安全的列表

列表(list)是最基本的集合。一个列表中的元素数量是不确定的,并且你可以添加、读取和删除任意位置上的元素。并发列表允许不同的线程在同一时刻对列表里的元素进行添加或删除,而不会产生任何数据不一致的问题。

在这个指南中,你将学习如何在你的并发应用程序中使用阻塞的列表。阻塞列表与非阻塞列表的主要区别是,阻塞列表有添加和删除元素的方法,如果由于列表已满或为空而导致这些操作不能立即进行,它们将阻塞调用的线程,直到这些操作可以进行。Java包含实现阻塞列表的LinkedBlockingDeque类。

你将使用以下两种任务来实现例子:

  • 添加大量数据到列表。
  • 从同一个列表中删除大量的数据。


准备工作…

这个指南的例子使用Eclipse IDE实现。如果你使用Eclipse或其他IDE,如NetBeans,打开它并创建一个新的Java项目。

如何做…

按以下步骤来实现的这个例子:

1.创建一个实现Runnable接口的Client类。


1 public class Client implements Runnable{

2.声明一个私有的、LinkedBlockingDeque类型的、参数化为String类的属性requestList。


1 private LinkedBlockingDeque requestList;

3.实现这个类的构造器,并初始化它的属性。


1 public Client (LinkedBlockingDeque requestList) {
2 this.requestList=requestList;
3 }

4.实现run()方法。使用requestList对象的put()方法,每秒往列表插入5个String对象。重复这个循环3次。


01 @Override
02 public void run() {
03 for (int i=0; i<3; i++) {
04 for (int j=0; j<5; j++) {
05 StringBuilder request=new StringBuilder();
06 request.append(i);
07 request.append(":");
08 request.append(j);
09 try {
10 requestList.put(request.toString());
11 } catch (InterruptedException e) {
12 e.printStackTrace();
13 }
14 System.out.printf("Client: %s at %s.\n",request,new Date());
15 }
16 try {
17 TimeUnit.SECONDS.sleep(2);
18 } catch (InterruptedException e) {
19 e.printStackTrace();
20 }
21 }
22 System.out.printf("Client: End.\n");
23 }

5.创建这个例子的主类,通过实现Main类,并实现main()方法。


1 public class Main {
2 public static void main(String[] args) throws Exception {

6.声明和创建参数化为String类、名为list的LinkedBlockingDeque。


1 LinkedBlockingDeque
2 list=new LinkedBlockingDeque(3);

7.创建和启动一个Thread对象来执行client任务。


1 Client client=new Client(list);
2 Thread thread=new Thread(client);
3 thread.start();

8.使用这个列表的take()方法,每300毫秒获取列表的3个字符串(String)对象。重复这个循环5次。将字符串(String)写入到控制台。


1 for (int i=0; ifor (int j=0; j<3; j++) {
2 String request=list.take();
3 System.out.printf("Main: Request: %s at %s. Size:%d\n",request,new Date(),list.size());
4 }
5 TimeUnit.MILLISECONDS.sleep(300);
6 }

9.写入一条信息表明程序的结束。


1 System.out.printf("Main: End of the program.\n");

它是如何工作的…

在这个指南中,你已使用参数化为String类的LinkedBlockingDeque来处理非阻塞并发列表的数据。

Client类使用put()方法添加字符串到列表中。如果列表已满(因为你已使用固定大小来创建它),这个方法阻塞线程的执行,直到列表有可用空间。

Main类使用take()方法从列表中获取字符串,如果列表为空,这个方法将阻塞线程的执行,直到列表中有元素。

在这个例子中,使用LinkedBlockingDeque类的这两个方法,如果它们在阻塞时被中断,将抛出InterruptedException异常。所以,你必须包含必要的代码来捕捉这个异常。

不止这些…

LinkedBlockingDeque类同时提供方法用于添加和获取列表的元素,而不被阻塞,或抛出异常,或返回null值。这些方法是:

  • takeFirst() 和takeLast():这些方法分别返回列表的第一个和最后一个元素。它们从列表删除返回的元素。如果列表为空,这些方法将阻塞线程,直到列表有元素。
  • getFirst() 和getLast():这些方法分别返回列表的第一个和最后一个元素。它们不会从列表删除返回的元素。如果列表为空,这些方法将抛出NoSuchElementExcpetion异常。
  • peek()、peekFirst(),和peekLast():这些方法分别返回列表的第一个和最后一个元素。它们不会从列表删除返回的元素。如果列表为空,这些方法将返回null值。
  • poll()、pollFirst()和 pollLast():这些方法分别返回列表的第一个和最后一个元素。它们从列表删除返回的元素。如果列表为空,这些方法将返回null值。
  • add()、 addFirst()、addLast():这些方法分别在第一个位置和最后一个位置上添加元素。如果列表已满(你已使用固定大小创建它),这些方法将抛出IllegalStateException异常。
目录
相关文章
|
1月前
|
网络协议 算法 Java
|
1月前
|
安全 算法 Java
Java中的线程安全集合
【2月更文挑战第23天】本文将介绍Java中的线程安全集合,包括它们的使用场景、优缺点以及如何在实际项目中应用。通过阅读本文,你将了解到线程安全集合的重要性以及如何在多线程环境下使用它们来提高程序的性能和稳定性。
30 0
|
1月前
|
安全 数据库连接 数据库
连接池的并发和线程安全
连接池的并发和线程安全
|
1月前
|
安全 Java 容器
线程安全的集合类
线程安全的集合类
|
2月前
|
Java 调度 开发者
JDK 21中的虚拟线程:轻量级并发的新篇章
本文深入探讨了JDK 21中引入的虚拟线程(Virtual Threads)概念,分析了其背后的设计哲学,以及与传统线程模型的区别。文章还将讨论虚拟线程如何简化并发编程,提高资源利用率,并展示了一些使用虚拟线程进行开发的示例。
|
6天前
|
Java API 调度
安卓多线程和并发处理:提高应用效率
【4月更文挑战第13天】本文探讨了安卓应用中多线程和并发处理的优化方法,包括使用Thread、AsyncTask、Loader、IntentService、JobScheduler、WorkManager以及线程池。此外,还介绍了RxJava和Kotlin协程作为异步编程工具。理解并恰当运用这些技术能提升应用效率,避免UI卡顿,确保良好用户体验。随着安卓技术发展,更高级的异步处理工具将助力开发者构建高性能应用。
|
25天前
|
算法 安全 Unix
【C++ 20 信号量 】C++ 线程同步新特性 C++ 20 std::counting_semaphore 信号量的用法 控制对共享资源的并发访问
【C++ 20 信号量 】C++ 线程同步新特性 C++ 20 std::counting_semaphore 信号量的用法 控制对共享资源的并发访问
28 0
|
30天前
|
负载均衡 Java 数据处理
【C++ 并发 线程池】轻松掌握C++线程池:从底层原理到高级应用(三)
【C++ 并发 线程池】轻松掌握C++线程池:从底层原理到高级应用
51 2
|
30天前
|
存储 监控 Java
【C++ 并发 线程池】轻松掌握C++线程池:从底层原理到高级应用(二)
【C++ 并发 线程池】轻松掌握C++线程池:从底层原理到高级应用
37 1
|
30天前
|
负载均衡 安全 Java
【C++ 并发 线程池】轻松掌握C++线程池:从底层原理到高级应用(一)
【C++ 并发 线程池】轻松掌握C++线程池:从底层原理到高级应用
57 2

热门文章

最新文章