关于 Executors.newSingleThreadExecutor() 的问题

2024-05-02

这是一个关于以下代码的程序流程的问题:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Test {
    public static void main(String args[]) {
        ExecutorService service = null;
        try {
            service = Executors.newSingleThreadExecutor();
            
            System.out.println("begin");
            service.execute(() -> System.out.println("Printing zoo inventory"));
            service.execute(() -> {
                for(int i = 0; i< 3; i++)
                    System.out.println("Printing record: " + i);
            });
            service.execute(() -> System.out.println("printing zoo inventory"));
        } finally {
            if(service != null)
                service.shutdown();
        }
    }
}

在上面的代码中,一旦我们越过“System.out.println("begin")...线程执行器就会一个接一个地执行以下每个操作任务(基本上是一个 Runnable lambda)。

我的理解是,考虑到线程执行器“服务”执行,这些“任务”(s.o.p(“打印...”)、for循环、s.o.p(“打印..”))将一个接一个地运行线程执行器上的每个 Runnable lambda。

除非 Runnable lambda 在当前行完成,否则程序流程不会移动到下一行,我是否正确?例如,除非 Runnable lambda 完成 s.o.p("printing Zoo inventory")...它不会在下一行启动下一个 Runnable lambda 吗?

如果当前线程执行器带有计算密集型的 Runnable lambda,会发生什么情况?在这种情况下,下一行(如果它包含另一个 Runnable lambda)..必须等到当前线程执行器完成任务?


Q & A

-“我是否正确,除非无法运行的 lambda 在当前行完成,否则程序流程不会移动到下一行?例如,除非可运行的 lambda 完成 s.o.p(“打印动物园库存”)...它不会启动下一行的下一个可运行 lambda?”

- 是的,你是对的。*

-"如果当前线程执行器带有计算密集型的 Runnable lambda,会发生什么情况?在这种情况下, 下一行(如果它包含另一个 Runnable lambda)..必须 等到当前线程执行器完成任务?"

- 是的,必须等待。*

-"你最爱的颜色?"

-Red.

( * ) 假设您正在检查来自ExecutorService,忽略主线程(及其调用以执行某些操作),并专注于池工作线程。主线程由自己运行,如果他们决定,某些实现也可以向其分配任务,这就是本文的原因.



Test & Compare

我将尝试将此执行器与多线程执行器进行比较,以显示两种方法之间的差异。

关于您的问题,重点是阻塞等待场景,根据所使用的执行器服务,给出的答案完全不同。使用第二个选项,答案将是:

  • 如果有工作人员空闲,即使当前生产线尚未完成,它也可以移动到下一条生产线。

  • 不,如果线程可用,它就不必等待。

  • Red.

SingleThreadExecutor

创建一个Executor that 使用单个工作线程 https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html#newSingleThreadExecutor(java.util.concurrent.ThreadFactory)操作关闭 无界队列。 任务是 保证顺序执行,并且不会超过一个任务 在任何给定时间都活跃.

池中只有一个线程,因此所有任务都分配给它。正如文档中所述,它必须按顺序执行所有这些操作。做一个简单的测试,例如:

service = Executors.newSingleThreadExecutor();
        
service.execute(() -> System.out.println("Printing zoo inventory"));
service.execute(() -> {
                        try {Thread.sleep(5000);    System.out.println("Woke up"); }
                        catch (InterruptedException e) {e.printStackTrace();}
                      });
service.execute(() -> System.out.println("Finish"));

Output

  Printing zoo inventory     // ---- [Thread 1] 
  //...5s 
  Woke up                    // ---- [Thread 1]
  Finish                     // ---- [Thread 1] -{x}- 

正如这张至少平庸的时间图所示:

   {task1}    {task2}                          {task3}
      ^          ^                                ^
      |          |                     (~5s)      |
  [Thread1]-->[Thread1]---------------------->[Thread1]->{x}   

调试它时,唯一可用的线程确认它是执行前两个任务的线程。图像示例来自原始OP的问题:

第三个任务的断点 - 已经完成了两个


MultiThreaded Pool https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html#newFixedThreadPool(int)

使用FixedThreadPool例如。当多个工作线程可用时,进程的行为会发生变化;对于本示例,设置了两个线程。

一如既往,应该仔细阅读文档:

创建一个重用线程池固定数量的线程 https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html#newFixedThreadPool(int)操作 脱离共享无界队列。在任何时候,最多 nThreads 个线程 将是主动处理任务。如果提交了额外的任务 当所有线程都处于活动状态时,它们将在队列中等待,直到 线程可用

稍微修改了测试,添加一些有关工作线程的信息并执行一些额外的任务。

volatile boolean wifeAlarm = false;
//...
service = Executors.newFixedThreadPool(2);

设置完成后,执行多个任务:

service.execute(() -> System.out.println("Woke up fast -" 
                      + Thread.currentThread().getName()));
service.execute(() -> 
{ 
  try {
         Thread.sleep(5000);    
         System.out.println("Woke up lazy - John where are you?? - {"+ 
                            Thread.currentThread().getName()+"}"); 
      } catch (InterruptedException e){}
       finally { wifeAlarm=true;}
 });
 service.execute(() -> System.out.println("Cleaning - {"
                       + Thread.currentThread().getName()+"}"));
 service.execute(() -> System.out.println("Making breakfast - {"
                       +Thread.currentThread().getName()+"}"));
 service.execute(() -> System.out.println("Flirt with neighbour - {"
                       +Thread.currentThread().getName()+"}"));
 service.execute(() -> System.out.println("Got her number - {"
                       +Thread.currentThread().getName()+"}"));
 service.execute(() -> System.out.println("Send hot af pic - {"
                       +Thread.currentThread().getName()+"}"));
 service.execute(() -> System.out.println("Remove all proof on phone - {"
                       +Thread.currentThread().getName()+"}"));
 service.execute(() -> 
 {
   try {
         while (!wifeAlarm)
             Thread.sleep(13);
         System.out.println("Just working my love - {"+ 
                            Thread.currentThread().getName()+"}"); 
       } catch (InterruptedException e) {}
  });

Output

Woke up fast - {pool-1-thread-1}
Cleaning - {pool-1-thread-1}
Making breakfast - {pool-1-thread-1}
Flirt with neighbour - {pool-1-thread-1}
Got her number - {pool-1-thread-1}
Send hot af pic - {pool-1-thread-1}
Remove all proof on phone - {pool-1-thread-1}
// ~4-5s
Woke up lazy - John where are you?? - {pool-1-thread-2}
Just working my love - {pool-1-thread-1}

这只是另一种可怕的表现:

   {task1} {task2}  {task3}  (..)  {task9}
      ^       ^        ^              ^                     (~5s)
      |   [Thread2]--- | -------------|---------(...)----------->{x}        
  [Thread1] ----->[Thread1]--(..)-[Thread1]----------------------->{x}   
              

简历中:约翰利用了这个新环境,取得了一些成就great感谢多线程池。

John 能够执行 7 个操作,而线程 2 执行 1 个操作。对于 John 来说更好的是,他能够在线程 2 完成分配的任务之前完成所有操作。约翰现在安全了,它将完成其任务并进入空闲状态,因为队列是空的。对约翰有好处。

  • thread-2被安排了task 2。但这次睡眠不会导致工作队列的增加,因为其他线程能够同时执行它们。
  • thread-1执行所有的4 vital tasks: 5、6、7 和 8。它还被分配了其他4个低优先级任务,能够在另一个线程“忙”时清空工作队列(sleeping).
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

关于 Executors.newSingleThreadExecutor() 的问题 的相关文章

  • Java 创建浮雕(红/蓝图像)

    我正在编写一个 Java 游戏引擎 http victoryengine org http victoryengine org 并且我一直在尝试生成具有深度的 3D 图像 您可以使用那些红色 蓝色眼镜看到 我正在使用 Java2D 进行图形
  • 如何从另一个xml文件动态更新xml文件?

    我想从另一个 xml 文件更新 xml 文件 我使用了一个 xml 文件 如下所示 one xml
  • 通过 InjectMocks Spy 注入对象

    我需要对一个类运行一系列单元测试 该类具有 Autowired Logger 实现 实现的基本思想是 Mock Logger logger InjectMocks TestedClass tested 但我想保存日志输出功能 Mockito
  • 使用 volatile bool 强制另一个线程等待是否安全? (C++)

    我读到的有关 volatile 的所有内容都说它永远不安全 但我仍然倾向于尝试它 而且我还没有看到这种特定场景被宣布为不安全 我有一个单独的线程来渲染场景 从主模拟线程中提取数据 这没有同步 并且工作正常 问题是 当程序退出时 渲染器需要停
  • Java 重写 hashCode() 得到 StackOverflowError

    所以我不太熟悉重写 hashCode 并且我似乎在 hashCode 方法中以某种方式进行了一些无限递归 这是我的场景 我有一个 DuplicateCache 类 它是一个缓存对象 用于检查系统中的重复对象 我有一个静态内部类 Duplic
  • shell脚本中是否有互斥/信号量机制?

    我正在 shell 脚本中寻找互斥 信号量 并发机制 考虑以下情况 除非 a 用户不关闭共享文件 否则 b 用户应该无法打开 更新它 我只是想知道如何在 shell 脚本中实现互斥量 信号量 临界区等 在 shell 脚本中实现锁定机制 文
  • 场景生成器删除 fxml 文件中的导入

    我使用场景构建器 Gluon Scene Builder JavaFX Scene Builder 8 1 1 来创建应用程序的 UI 并使用 Eclipse 开发 JavaFX 现在 每次我在场景生成器中保存某些内容时 它都会从 fxml
  • 使用 java 按电子邮件发送日历邀请

    我正在尝试使用 java 发送每封电子邮件的日历邀请 收件人收到电子邮件 但不会显示接受或拒绝的邀请 而是将该事件自动添加到他的日历中 我正在使用 ical4j jar 构建活动 邀请 private Calendar getInvite
  • iPhone SDK - 在后台线程中运行重复进程

    我有一个iPhone我想在其中每隔一段时间在后台执行一个方法的应用程序1第二 所以在我的主线程中 我有以下代码UIViewController viewDidLoad NSTimer timerWithTimeInterval 1 0 ta
  • Apache Commons CLI:替代已弃用的 OptionBuilder?

    IntelliJ 显示此示例代码中不推荐使用 OptionBuilderhttp commons apache org proper commons cli usage html http commons apache org proper
  • 如何使用 Mockito 和 Junit 模拟 ZonedDateTime

    我需要模拟一个ZonedDateTime ofInstant 方法 我知道SO中有很多建议 但对于我的具体问题 到目前为止我还没有找到任何简单的解决办法 这是我的代码 public ZonedDateTime myMethodToTest
  • 如何为 Jackson 编写一个包罗万象的(反)序列化器

    当您提前知道类型时 编写自定义序列化器非常容易 例如 MyType一个人可以写一个MyTypeSerializer extends StdSerializer
  • 从 Stax XMLStreamReader 读取以解组部分

    我正在使用 Stax 游标 API 从大型 xml 文件中提取数据 当前 我转到特殊标签的开头并使用 JAXB 解组该标签 这对于格式良好的 xml 文件效果很好 但不久前我有一个文档 其中数十万个标签中有一个未关闭 JAXB 使用 XML
  • 如何在keycloak中动态编辑standalone.xml文件

    我正在尝试通过 docker 编辑standalone xml 并尝试添加 但 keycloak 正在使用它standalone xml 但我可以看到standalone xml 文件中的更改 我需要在standalone xml 文件中添
  • 使用 Java 从 S3 上的文件在 S3 上创建 zip 文件

    我在 S3 上有很多文件 需要对其进行压缩 然后通过 S3 提供压缩文件 目前 我将它们从流压缩到本地文件 然后再次上传该文件 这会占用大量磁盘空间 因为每个文件大约有 3 10MB 而且我必须压缩多达 100 000 个文件 所以一个 z
  • 来自客户端的超时 Web 服务调用

    我正在使用 RestEasy 客户端调用网络服务 一项要求是 如果调用运行时间超过 5 秒 则中止 超时调用 我如何使用 RestEasy 客户端实现这一目标 我只看到服务器端超时 即如果在一定时间内未完成请求 Rest Easy 网络服务
  • Spock模拟inputStream导致无限循环

    我有一个代码 gridFSFile inputStream bytes 当我尝试这样测试时 given def inputStream Mock InputStream def gridFSDBFile Mock GridFSDBFile
  • 重写Object类的finalize()方法有什么用?

    据我所知 在java中如果我们想手动调用垃圾收集器 我们可以执行System gc 1 我们在重写的finalize 方法中做了哪些操作 2 如果我们想手动调用JVM垃圾收集器 是否需要重写finalize 方法 我们在重写的 Finali
  • Java中获取集合的幂集

    的幂集为 1 2 3 is 2 3 2 3 1 2 1 3 1 2 3 1 假设我有一个Set在爪哇中 Set
  • MongoDB Java 驱动程序:MongoCore 驱动程序与 MongoDB 驱动程序与 MongoDB 异步驱动程序

    MongoDB Java 驱动程序有三种不同的驱动程序选项 核心驱动 MongoDB 驱动程序 MongoDB 异步驱动程序 The 驱动程序描述页面 https docs mongodb org ecosystem drivers jav

随机推荐