当前位置:首页 > 数码 > 四种常见线程池原理详解-掌握并发编程必备知识 (四种常见线程池)

四种常见线程池原理详解-掌握并发编程必备知识 (四种常见线程池)

admin6个月前 (05-07)数码23

线程池是一种用于管理线程的机制,它提供了预先创建的线程集合,这些线程可以重复利用来执行任务。

Java 中的 ExecutorService 接口定义了一组用于管理线程池的方法。ExecutorService 的常见实现包括:

  • newFixedThreadPool(固定数目线程的线程池)
  • newCachedThreadPool(可缓存线程的线程池)
  • newSingleThreadExecutor(单线程的线程池)
  • newScheduledThreadPool(定时及周期执行的线程池)

newSingleThreadExecutor

newSingleThreadExecutor 创建一个单线程的线程池。这意味着只有一个线程可以同时执行任务。该线程池适用于串行执行任务的场景,一个任务一个任务地执行。

掌握并发编程必备知识
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
  return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory));
}
  

newSingleThreadExecutor 特点

  • 核心线程数:1
  • 最大线程数:1
  • 阻塞队列是无界队列 LinkedBlockingQueue,可能会导致 OOM
  • keepAliveTime:0

newSingleThreadExecutor 工作流程

1. 提交任务 2. 线程池是否有一条线程在,如果没有,新建线程执行任务 3. 如果有,将任务加到阻塞队列 4. 当前的唯一线程,从队列取任务,执行完一个,再继续,一个线程执行任务

newFixedThreadPool

newFixedThreadPool 创建一个固定数目线程的线程池。这意味着线程池始终保持指定数目的线程,无论负载如何。该线程池适用于处理 CPU 密集型的任务,确保 CPU 在长期被工作线程使用的情况下,尽可能少的分配线程,即适用执行长期的任务。

public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
  return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory);
}
  

newFixedThreadPool 特点

  • 核心线程数和最大线程数大小一样
  • 没有所谓的非空闲时间,即 keepAliveTime 为 0
  • 阻塞队列为无界队列 LinkedBlockingQueue,可能会导致 OOM

newFixedThreadPool 工作流程

1. 提交任务 2. 如果线程数少于核心线程,创建核心线程执行任务 3. 如果线程数等于核心线程,把任务添加到 LinkedBlockingQueue 阻塞队列 4. 如果线程执行完任务,去阻塞队列取任务,继续执行

newCachedThreadPool

newCachedThreadPool 创建一个可缓存线程的线程池。这意味着线程池可以创建无限数量的线程,并在任务被处理后终止空闲线程。该线程池适用于爆发式任务或短期任务。

public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
  return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), threadFactory);
}
  

newCachedThreadPool 特点

  • 核心线程数为 0
  • 最大线程数为 Integer.MAX_VALUE,即无限大,可能会因为无线创建线程,导致 OOM
  • 阻塞队列是 SynchronousQueue,非核心线程空闲存活时间为 60s

newCachedThreadPool 工作流程

1. 提交任务 2. 因为没有核心线程,所以任务会直接加到 SynchronousQueue 3. SynchronousQueue 阻塞队列会立即将任务转移到一个新创建的线程中执行 4. 当提交任务速度大于处理任务的速度时,每次提交一个任务,就必然会创建一个线程。极端情况下会创建过多的线程,耗尽 CPU 和内存资源。 5. 由于空闲 60 秒的线程会被终止,长时间保持空闲的 CachedThreadPool 不会占用任何资源。

newScheduledThreadPool

newScheduledThreadPool 创建一个定时及周期执行的线程池。这意味着线程池可以安排任务在指定时间或以指定延迟执行。该线程池适用于定时任务或周期性任务。

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory) {
  return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
}
  

newScheduledThreadPool 特点

  • 核心线程数:指定的大小
  • 最大线程数:无限
  • 阻塞队列:无界队列 DelayQueue
  • keepAliveTime:无限

newScheduledThreadPool 工作流程

1. 提交任务 2. 任务被添加到 DelayQueue 阻塞队列,并指定执行时间 3. 核心线程从队列中取出任务,在指定时间执行任务 4. 如果核心线程全部 занят,则创建新的线程执行任务 5. 非核心线程空闲时间无限,不会被终止

每种线程池都有自己的特点和适用场景,开发者需要根据实际需求选择合适的线程池类型。


c线程被打断异常

线程中断方法主要是两种()是否为中断状态interrupt()设置为中断线程中断,并非真正的线程中断,而只是将线程的中断状态标识设置为true,由线程自己根据状态标识进行相应的业务处理逻辑,而线程实际上还在进行。 要区别于InterruptedException异常,一般的,线程会因为BlockingQueue#put、BlockingQueue#take、Object#wait、Thread#sleep以上状态被打断而抛出异常,这个异常是真正的线程中断,而与线程的中断状态标识没有任何关系,标识状态依然为false。 所以,这就需要注意一个问题,千万不能捕获了InterruptedException而不做中断处理,否则业务逻辑依然以为你没有中断,依然走正常的异常逻辑二、示例代码文章知识点与官方知识档案匹配Java技能树首页概览 人正在系统学习中打开CSDN APP,看更多技术内容线程中断的几种方式_坚持与努力的博客_线程中断有三种方法可以使终止线程。 1. 使用退出标志,使线程正常退出,也就是当run方法完成后线程终止。 2. 使用stop方法强行终止线程(这个方法不推荐使用,因为stop和suspend、resume一样,也可能发生不可预料的结果)。 3. 使用interrupt方法中断线程...继续访问线程中断解析_叶小希的博客_线程中断状态// 如果线程不响应中断 无法中断线程 (); // jvm不建议使用的方法 会让线程之间介绍,线程状态未知的情况下 将线程结束 // (); } 常见check的代码 if(()){// 会清理掉中断状态 ...继续访问java 线程 异常中断_java多线程并发之旅-19-InterruptedException 中断异常处理及中断机制...引言如果对 Java 中断没有一个全面的了解,可能会误以为被中断的线程将立马退出运行,但事实并非如此。 中断机制是如何工作的?捕获或检测到中断后,是抛出 InterruptedException 还是重设中断状态以及在方法中吞掉中断状态会有什么后果? 与中断相比又有哪些异同?什么情况下需要使用中断?线程池中的异常如何处理?中断处理的最佳实践?线程中断基础知识1、interrup...继续访问什么是线程中断?下面的这断代码大家应该再熟悉不过了,线程休眠需要捕获或者抛出线程中断异常,也就是你在睡觉的时候突然有个人冲进来把你吵醒了。 try { (3000); } catch (InterruptedException e) { (); } 此时线程被打断后,代码会继续运行或者抛出异常结束运行,这并不是我们需要的中断线程的作用。 到底是什么是线程中断? 线程中断即线程运行过程中被其他线程给打断了,它与 stop 最大的区别是:stop 是由系继续访问java阻塞线程中断_线程阻塞,线程中断,何时以及如何响应中断2. sleep()造成的线程阻塞可以中断,而IO和synchronized造成的阻塞不可中断(即不能响应中断请求) 中断 不可中断阻塞 的方法: 关闭在其上发生阻塞的底层资源.比如 IO阻塞时不可中断, 在关闭这个IO时便可以中断. ...继续访问【线程】线程中断详解文章目录中断线程判断线程是否被中断如何中断线程(中断原理)底层中断异常处理方式 中断线程 线程的()方法是中断线程,将会设置该线程的中断状态位,即设置为true,中断的结果线程是死亡、还是等待新的任务或是继续运行至下一步,就取决于这个程序本身。 线程会不时地检测这个中断标示位,以判断线程是否应该被中断(中断标示值是否为true)。 它并不像stop方法那样会中断一个正在运行的线程。 判断线程是否被中断 判断某个线程是否已被发送过中断请求,请使用继续访问并发编程之LockSupport的 park 方法及线程中断响应并发编程之LockSupport的 park 方法及线程中断响应继续访问Java并发基础学习(二)——线程的停止和中断前言 上一篇博客简单介绍了线程启动的方式,这一篇博客打算介绍一下如何停止线程,Java中停止线程相对来说就比较麻烦了,如何正确的停止线程其实也是一个比较常见的面试考题,需要详细总结一下。 线程停止的原理 Java中线程的停止并不是像关闭一个开关一样,直接停止线程,Java中的线程停止原理有点类似于计算机组成原理中对中断的处理,首先关闭中断标志位,让后响应中断,然后处理中断。 Java中线程的处理也可以看成大致的这个过程——**线程本身响应外部的中断通知,然后将中断标志位复位,但是什么之后线程停止,由线程本身继续访问线程响应中断首先介绍下Thread的两个方法: interrupt():设置当前中断标记为true isInterrupted():检查线程的中断标记 @Slf4j public class StopThread implements Runnable { public static void main(String[] args) throws InterruptedException { ...继续访问对于Java线程中断的理解,哪种情况下会响应中断?哪种情况下不响应中断?最近在学习JUC框架的时候,发现了很多工具类都是支持可中断的,如AQS、FutureTask都是可以在线程执行中,支持对于中断的响应,所以需要对线程中断有个了解,才能更好的学习JUC的源码。 线程中断的作用: 线程中断可以使一个线程从等待状态变成就绪状态,如果中断的线程正处于运行状态,那么这个中断是不会用任何作用的(表面上不会影响正在运行的线程),线程恢复到就绪状态后,可以继续执行逻辑代码,想要让一个线程从等待状态中恢复过来有三种发送:一.等待超时,二.得到一个通知...继续访问线程篇——线程的停止与中断interrupt 还是先看下Thread类中interrupt方法的注释: Interrupts this thread. Unless the current thread is interrupting itself, which is always permitted, the checkAccess method of this thread is invoked, which may cause a SecurityException to be thrown. If this thread i继续访问线程的中断我们都知道线程被终止一般有两个原因:一是run()方法正常执行完毕而自然死亡;二是因为一个没有捕获的异常终止了run方法而异外死亡。 当一个线程在正常执行完毕之前被中断是一件很可怕的事情,会出现很多意想不到的事情,比如不能归还锁而造成死锁现象,stop()方法和destroy()方法就是因此而被废弃的。 在前一篇博客中,我们尝试了利用一些变量以指示目标线程应该停止运行来达到线程终止的目的。 在Jav...继续访问java关闭未执行完的线程_发现在JAVA中完全没办法用另一个线程去中断一个正在运行的线程,...引用来自“爱吃大肉包”的答案引用来自“Grrrr”的答案真搞不懂,sun 已经推荐使用ExecutorService框架来处理thread了,为什么还是不用提供了管理终止的方法,以及可为跟踪一个或多个异步任务执行状况而生成 Future 的方法。 可以关闭ExecutorService,这将导致其拒绝新任务。 提供两个方法来关闭ExecutorService。 shutdown()方法...继续访问线程中断Thread的interrupt()方法什么时候需要关闭一个线程? 下面简单的举例情况: 比如我们会启动多个线程做同一件事,比如抢的火车票,我们可能开启多个线程从多个渠道买火车票,只要有一个渠道买到了,我们会通知取消其他渠道。 这个时候需要关闭其他线程 很多线程的运行模式是死循环,比如在生产者/消费者模式中,消费者主体就是一个死循环,它不停的从队列中接受任务,执行任务,在停止程序时,我们需要一种”优雅”的方法以关闭该线程 在一些场景中,比如从第三方服务器查询一个结果,我们希望在限定的时间内得到结果,如果得不到,我们会希望取消该任务继续访问终止线程的方法转载自:终止线程的三种方法 1. 使用退出标志,使线程正常退出,也就是当run方法完成后线程终止。 2. 使用stop方法强行终止线程(这个方法...继续访问线程中断线程中断就是处于运行状态的线程被强制打断。 线程中断总体来说有三种方法:正常退出、stop暴力停止、interrupt异常停止。 其中使用stop()方法是不安全的,可能导致数据不同步或者资源无法回收,目前stop()方法已经被标注为作废方法。 一般使用interrupt停止线程,这里有几个与之相关的方法: public void interrupt() {} // 中断线程 public boo...继续访问Thread的中断机制(interrupt)先看收集了别人的文章,全面的了解下java的中断: 中断线程 线程的()方法是中断线程,将会设置该线程的中断状态位,即设置为true,中断的结果线程是死亡、还是等待新的任务或是继续运行至下一步,就取决于这个程序本身。 线程会不时地检测这个中断标示位,以判断线程是否应该被中断(中断标示值是否为true)。 它并不像stop方法那样会中断一个正在运行的线程。 判断线程...继续访问中断的线程化处理中断的线程化处理 复杂、耗时的事情,尽量使用内核线程来处理。 上节视频介绍的工作队列用起来挺简单,但是它有一个缺点:工作队列中有多个 work,前一个 work 没处理完会影响后面的 work。 解决方法有很多种,比如干脆自己创建一个内核线程,不跟别的 work 凑在一块了。 对于中断处理,还有另一种方法:threaded irq,线程化的中断处理。 中断的处理仍然可以认为分为上半部、下半部。 上半部用来处理紧急的事情,下半部用一个内核线程来处理,这个内核线程专用于这个中断。 你可以只提供 thread_fn,继续访问therading——多线程2thread线程类基本介绍 class (group=None, target=None, name=None, args=(), kwargs={}) 应该始终以关键字参数调用该构造函数。 参数有: group应该为None;被保留用于未来实现了ThreadGroup类时的扩展。 target是将被run()方法调用的可调用对象。 默认为None,表示不调用任何东西。 name是线程的名字。 默认情况下,以“Thread-N”的形式构造一个唯一的名字,N是一个小的十进制整数.继续访问java线程中断【README】 本文po出了; 本文部分内容转自:这篇博文写的非常好 Thread的中断机制(interrupt) - 寂静沙滩 - 博客园先看收集了别人的文章,全面的了解下java的中断:中断线程线程的()方法是中断线程,将会设置该线程的中断状态位,即设置为true,中断的结果线程是死亡、还是等待新的任务【1】使用()中断【非】阻塞状态继续访问最新发布 线程中断方法因为volatile能保证在多线程之间,一旦变量修改,能够立马通知到其他持有该变量的线程值被改变。 所以我们可以利用volatile这个特性来实现线程中断。 interrupted()查询当前线程阻塞状态,并将状态设置为false。 备注操作线程不能处于sleep,wait,join,不然会抛出异常。 interrupt()设置线程状态为true。 isInterrupt()查询当前线程阻塞状态。 ...继续访问java线程的中断与恢复_Java 如何中断和恢复线程的执行一、线程的状态线程可以阻塞于四种状态:1、当线程执行()时,它一直阻塞到指定的毫秒时间之后,或者阻塞被另一个线程打断;2、当线程碰到一条wait()语句时,它会一直阻塞到接到通知notify()、被中断、经过了指定时间为止(若有超时值的话)3、线程阻塞与不同I/O的方式3.1. 常见的一种方式是InputStream的read()方法,该方法一直阻塞到从流中读取一个字节的数...继续访问线程响应中断

java开发工程师必须要学的技术有哪些?

学习内容:初级部分Java 程序设计基础,包括 J2sdk基础、Java面向对象基础、Java API使用、数据结构及算法基础、Java AWT图形界面程序开发;J2SE平台Java程序设计,包括Swing图形程序设计, Socket网络应用程序设计,对象序列化,Java 常用数据结构,Applet,流和文件,多线程程序设计;Java桌面系统项目开发,4~5人组成一个项目组,项目大小为(15人*工作日);Linux的基本操作,Linux下的Java程序开发,Linux系统的简单管理;Oracle数据库,包括SQL/PLSQL;数据库和数据库设计;简单掌握ORACLE9i 数据库的管理;[2] 中级部分Java Web应用编程,包括 Java Oracle 编程,即JDBC;JavaWeb编程,包括JSP、Servlet,JavaBean;Java应用编程,包括Weblogic、Websphere、Tomcat;以及利用Jbuilder开发Java程序;MVC与Struts,学习业界通用的MVC设计模式和Struts架构;Java B/S商务项目开发,4~5人一个项目组,项目大小为(25人*工作日左右)高级部分J2ME程序设计,包括J2EE程序、J2ME;Java高级程序设计(J2EE),包括J2EE体系结构和J2EE技术、EJB;Weblogic使用、 JBuilder开发;Java和XML,包括Java Web Service,JavaXML, 业界主流XML解析器程序设计;软件企业规范和软件工程,包括UML系统建模型和设计(Rational Rose 200x)软件工程和业界开发规范;CVS版本控制、Java Code书写规范;J2EE商务应用系统项目开发,4~5人一个项目组,项目大小为(25人*工作日左右)。 ………………………………………………………………………………………………看你问的问题,应该是对java很感兴趣,其实你可以自学java。 关于如何学习java,我刚才看到一篇很不错的文章,是一个农民工介绍自己如何自学java,并找到Java的工作,里面介绍了他的学习方法和学习过程,希望对你有帮助。 我是一名地地道道的农民工,生活在经济落后的农村,有一个哥哥和一个弟弟,父母都是地道的农民,日出而作,日落而息,我从小到大学习一直很好,从小学到高一都,成绩在全级一直名列前茅,这样我也顺利了考上省的重点高中,然而,每个学期开学是家里最为难的时候,每次交学费都让父母发愁许久,家里为了给我筹钱读书,都借了不少钱,才让我读上高中。 我知道我读到高中家里已经欠了好多债,为了减轻家里的负担,我选择了退学。 2009年我高一退学,为了给家里还债,干过建筑工地的小工,搞过塑料制品加工,送水工等等。 很工资都很低,一个月也就1000多,加上加班费一个月能拿2000多一点,我每个月都向家里寄回800-1000元,到了2011年末,一次偶然的机会我接触了Java,听说Java的前景挺不错,工资相对于我一个农民工来说简直是天文数字,于是我在新华书店买了几本Java的书,尽管白天辛苦工作,晚上回来还是坚持看书,但有于基础太差很多都很不明白,但还是坚持看,一有看1-2个小时Java的书,看着看着许多基础都慢慢的学会了,但那些比较难的还是看不懂,后来还买了有些关于框架的书,还是看不懂,这样断断续续的持续了半年多,觉得自己Java的基础都差不多懂了,但框架还是看不懂,还有最缺的项目经验,看了很多招聘Java程序员的简介都要项目经验,相对我一个农民工来连框架都弄不明白,想找一份Java工作对我来说简直是奢侈。 我只想学Java,并不敢想以后能从事Java的工作。 有一次,在网络上看到一篇让我很鼓舞的文章,是一个Java高手介绍在没有基础的朋友怎么自学入门Java,文章写的很好,包含了如何学习,该怎么学习,他提到一个方法就是看视频,因为看书实在太枯燥和费解的,不少是我们也看不懂,这点我真的很认同,我自己看书都看了很久才学会基础。 曾经有想过参加培训,但是上万元的培训费让我望而却步,我工资这么低,每个月还有向家里汇钱,加上城市消费比较高,虽然每个月只有几百剩下,但是相对于上万万学费和四个月的吃住费用逼我连想不敢想。 于是我决定看视频,我就去搜索Java的视频,虽然我零星的找到一些Java的视频,但是都不系统。 最重要连项目都没有。 后来我找到一份很好的视频,是IT学习联盟这个网站一套视频叫<<零基础Java就业班>>的教程还不错,很完整。 还赠送11个顶级企业项目。 价格很合理,于是我买下来。 于是开始了我的自学Java的路,收到光盘后,我就开始学习,刚开始学习还不错,是从零基础教起,老师幽默风趣而又轻松的课堂教课,使我发现原来学习JAVA并不是一件很难的事情。 因为我本来基础还不错,前面的基础看一篇我就过去了,到了框架,我觉不又不是很难,可能老师太牛了,他能把复杂的问题讲的比较通俗易懂,有些难点的地方我还是连续看了五六次,把他弄懂。 每天下午6点下班后,吃了饭,马上跑回家。 看视频,买了几本笔记本。 当时,为了编程还花几百元了台二手的台式电脑,配置一般,但编程是足够的。 一边看视频,一边记笔记,把重点都记下来,还一边跟着老师敲代码,为了能尽早学会Java。 每天都坚持学5-6个小时。 经常学到晚上一点多才睡觉。 星期六,日不用上班,每天7点多起床,学到晚上11,12点。 那段时间特别辛苦,特别累。 在学习Java的三个多月里,除了吃饭睡觉工作,剩余的时间都在学习,因为我知道自己的计算机基础不是很好,也没有学过什么计算机,只是学了些Java基础,相对于那些科班的人来说我要比他们付出更多的努力。 我只能咬紧牙关,坚持下去,我不能放弃,我要完成我的梦想,我要让我的家人过上好日子。 终于三个多月后我把Java教程里的内容和项目都学完了,在学项目的过程中我发现项目特别重要,他能把你学过的知识全部联系起来,能更好的理解你所学的知识。 还有学习过程中,动手很重要,要经常跟着老师动手敲,动手吧,跟着做,一行一行的跟着敲,再试着加一些自己的功能,按照自己的思路敲一些代码,收获远比干听大的多。 如果遇到暂时对于一些思路不能理解的,动手写,先写代码,慢慢你就会懂了。 这套视频还赠送了11个顶级企业项目,对于我没有任何经验的人来说,这个太重要了,还有在学习项目是提升能力最快的方法。 项目能把所有的知识点全都连到一起了,不再是分散的,而是形成一个整体了。 那种感觉是仅仅深入钻研知识点而不写真实项目的人所不能体会的。 一个项目就是一根绳子可以把大片的知识串到一起。 就这样,我用了两个月也把项目给学完了。 其实学完教程差不错就达到就业水平,但是我可能觉得自己学历低还是把那11个顶级企业项目才去找工作。 接着我就到51job疯狂的投简历,因为我的学历问题,初中毕业,说真的,大公司没有人会要我。 所以我头的都是民营的小公司,我希望自己的努力有所回报。 没有想过几天后,就有面试了,但是第一次面试我失败了,虽然我自认为笔试很好,因为我之前做了准备,但是他们的要求比价严格,需要有一年的项目经验,所以我没有被选中。 后来陆续面试了几加公司,终于功夫不负有心人,我终于面试上了一家民营的企业。 公司规模比较小,我的职务是Java程序员。 我想我比较幸运,经理看中我的努力,就决定吕勇我,开的工资是3500一个月,虽然我知道在北京3500只能过温饱的生化,但是我想我足够了,比起以前的工资好了些,以后可以多寄些钱回家。 我想只要我继续努力。 我工资一定会翻倍的。 把本文写出来,希望能让和我一样的没有基础的朋友有信心,其实我们没有自卑,我们不比别人笨,只有我们肯努力,我们一样会成功。

免责声明:本文转载或采集自网络,版权归原作者所有。本网站刊发此文旨在传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及版权、内容等问题,请联系本网,我们将在第一时间删除。同时,本网站不对所刊发内容的准确性、真实性、完整性、及时性、原创性等进行保证,请读者仅作参考,并请自行核实相关内容。对于因使用或依赖本文内容所产生的任何直接或间接损失,本网站不承担任何责任。

标签: 线程池

“四种常见线程池原理详解-掌握并发编程必备知识 (四种常见线程池)” 的相关文章

揭秘线程池的七大参数-深化了解其性能和作用 (线程线程池)

揭秘线程池的七大参数-深化了解其性能和作用 (线程线程池)

问:可以说一下线程池吗? 关于线程池的疑问,大少数面试官会问线程池的几个参数的含意,当天就间接聊一聊线程池ThreadPoolExecutor。 先说下线程池中几个参数的含意:...

Java中线程池的优点和使用方法 (java中线程池的参数)

Java中线程池的优点和使用方法 (java中线程池的参数)

线程简介 线程是计算机中执行代码的最小单位,它可以在程序中独立运行,执行特定的任务。线程是稀缺的资源,过多地创建线程会消耗大量的系统资源,并降低系统的稳定性。在高并发的场景下,频繁地创建和销...

并非所有任务都合适-ForkJoinPool-使用-合理的 (并非所有任务的英文)

并非所有任务都合适-ForkJoinPool-使用-合理的 (并非所有任务的英文)

The Stream API is a powerful tool that can be used to process data in a concise and efficient mann...