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

简介:

使用阻塞线程安全的列表

列表(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异常。
目录
相关文章
|
10月前
|
Java API 调度
从阻塞到畅通:Java虚拟线程开启并发新纪元
从阻塞到畅通:Java虚拟线程开启并发新纪元
500 83
|
机器学习/深度学习 消息中间件 存储
【高薪程序员必看】万字长文拆解Java并发编程!(9-2):并发工具-线程池
🌟 ​大家好,我是摘星!​ 🌟今天为大家带来的是并发编程中的强力并发工具-线程池,废话不多说让我们直接开始。
430 0
|
设计模式 运维 监控
并发设计模式实战系列(4):线程池
需要建立持续的性能剖析(Profiling)和调优机制。通过以上十二个维度的系统化扩展,构建了一个从。设置合理队列容量/拒绝策略。动态扩容/优化任务处理速度。检查线程栈定位热点代码。调整最大用户进程数限制。CPU占用率100%
649 0
|
10月前
|
存储 Java 调度
Java虚拟线程:轻量级并发的革命性突破
Java虚拟线程:轻量级并发的革命性突破
523 83
|
7月前
|
设计模式 缓存 安全
【JUC】(6)带你了解共享模型之 享元和不可变 模型并初步带你了解并发工具 线程池Pool,文章内还有饥饿问题、设计模式之工作线程的解决于实现
JUC专栏第六篇,本文带你了解两个共享模型:享元和不可变 模型,并初步带你了解并发工具 线程池Pool,文章中还有解决饥饿问题、设计模式之工作线程的实现
500 2
|
存储 缓存 安全
JUC并发—11.线程池源码分析
本文主要介绍了线程池的优势和JUC提供的线程池、ThreadPoolExecutor和Excutors创建的线程池、如何设计一个线程池、ThreadPoolExecutor线程池的执行流程、ThreadPoolExecutor的源码分析、如何合理设置线程池参数 + 定制线程池。
JUC并发—11.线程池源码分析
|
安全 Java
线程安全的艺术:确保并发程序的正确性
在多线程环境中,确保线程安全是编程中的一个核心挑战。线程安全问题可能导致数据不一致、程序崩溃甚至安全漏洞。本文将分享如何确保线程安全,探讨不同的技术策略和最佳实践。
320 6
|
Java API 调度
【JavaEE】——多线程(join阻塞,计算,引用,状态)
【JavaEE】——多线程,join,sleep引起的线程阻塞,多线程提升计算效率,如何获取线程的引用和状态
|
10月前
|
Java API 微服务
为什么虚拟线程将改变Java并发编程?
为什么虚拟线程将改变Java并发编程?
455 83

热门文章

最新文章