【问题标题】:CICSCallable thread does not endCICSCallable 线程没有结束
【发布时间】:2020-11-02 09:10:22
【问题描述】:

我有一个将在 IBM Liberty 应用服务器上运行的 Java 应用程序;我正在尝试将多线程与CICSExecutorService 一起使用。这是我的用例:

  1. 创建CICSExecutorService的实例;
  2. 从实现 CICSTransactionCallable 的类创建一个线程(对 Db2 进行简单的选择查询);
  3. 将线程提交给执行器服务;
  4. 关闭执行器服务,等待终止;

这是代码:

    CICSExecutorService cicsExecutorService = new CICSExecutorService();
    //CICSReadingJob is the class that implements CICSTransactionCallable interface
    CICSReadingJob<String> thread1 = new CICSReadingJob<>();
    Future<List<String>> future1 = cicsExecutorService.submit(thread1);

    cicsExecutorService.shutdown();
    cicsExecutorService.awaitTermination(100, TimeUnit.SECONDS);

我使用标准的 java executor 服务做了一些简单的本地测试,其行为是,在调用 shutdown 和 awaitTermination 方法后,程序等待线程终止(除非线程的执行时间超过 100 秒,指定的超时),然后执行继续。问题是,当我使用上面的代码时,我看到了一种不同的行为:事实上,如果线程(唯一与CICSExecutorService 连接的线程)在 (到达call() 方法的末尾)。我也尝试使用静态方法CICSExecutorService.runAsCICS() 而不是cicsExecutorService.submit(),但我得到了相同的结果。似乎子线程在到达call() 方法的末尾时也保持活动状态,因此awaitTermination 一直等到超时结束。有什么建议吗?

【问题讨论】:

    标签: java multithreading executorservice websphere-liberty cics


    【解决方案1】:

    CICS 内部已经提供了一个 CICSExecutorService 实例。它可以直接从静态 API 方法(例如 runAsCICS() 方法)访问。您不(也不应该)尝试构建 ExecutorService,或自己控制 ExecutorService - 这一切都是在内部完成的,以确保观察到正确的环境和生命周期。类上有一个公共构造函数,纯粹是为了满足声明式服务的要求,而不是一般用途。看起来 Javadoc 应该更明确地说明预期用途 - 我会看看是否可以更新。

    此页面提供了有关如何使用 API 的更多详细信息(尽管是针对 Runnable 而不是 Callable,但 API 遵循相同的模式): https://www.ibm.com/support/knowledgecenter/SSGMCP_5.5.0/applications/developing/java/dfhpjgo.html

    请注意,您正在向 Executor 提交“Callable”,而不是线程。 CICSExecutorService 将在后台决定在启用“CICS”的线程上运行您的可调用对象 - 允许在内部进行线程池和重用以及其他此类智能。

    此外,如果您正在驱动 CICS Liberty 应用程序,您通常不需要自己生成新的启用 CICS 的线程 - 应用程序将隐式处理多个并发请求(通常是 Web 请求)。

    从代码 sn-p 我无法确定您的应用程序试图实现什么,但您提交的 Callable 对象应该有它的 call() 方法驱动完成,此时 CICS 任务将结束,并且线程它在其上运行将返回到 ExecutorService 的线程池。该线程将在该池中保持休眠,但不再与 CICS 事务相关联(准备好被另一个事务重用)。因此,如果您明确尝试确定线程是否已终止,那么您会感到失望,因为它们不会在 Liberty 环境中终止,直到 JVM 服务器被禁用。

    通常在使用 runAsCICS() 方法时,您提交 Callable 并取回 Future 对象。然后使用该 Future 对象来确定提交的工作何时完成。您不应尝试直接等待或操作 ExecutorService。

    希望对您有所帮助,但如果您仍然遇到问题,请发布更多测试应用程序并描述您想要实现的目标,以便我们提供更好的指导。谢谢。

    【讨论】:

    • 感谢您的回答;因此,如果我每次需要使用新线程时都正确理解,我必须使用 CICSExecutorService.runAsCics();我不能直接“停止”父线程的执行以等待子线程的终止,但我应该检查 Futures 的状态以了解线程是否完成;对吗?
    • 是的,如果您需要在启用 CICS 的线程上生成异步操作,超出对 CICS JVM 请求的并发多线程能力,那么您应该使用 CICSExecutorService.runAsCICS() 提交每个工作.使用返回的 Future 对象,您可以选择“等待”或“轮询”以在父线程中完成,也可以让它们异步完成。父操作和子操作都将在不同的 CICS 事务下的不同线程上运行,并且父操作可以在子操作之前完成 - 或者它可以等待一个或多个。
    • 我怎么能等到每个孩子都被终止(显然没有 while() 列表 futere.isDone )?我也找不到(阅读文档)添加回调以在线程完成时运行的方法(例如返回 CompletableFuture 的东西)
    【解决方案2】:

    如果您想将一堆子线程作为 CICS 任务启动并等待所有子线程终止,您也可以使用 CICS Async API 执行此操作。这也有一个 JCICS 接口,CICSDev GitHub上提供了一组示例@

    【讨论】:

    • 感谢您的回复;不幸的是,红皮书和 Github 示例几乎只涉及 COBOL; java中关于异步操作的资料很少。
    • 我找到了这个简单的示例,它说明了启动子事务并获取结果的基本用例。 AsyncService asyncServ = new AsyncServiceImpl(); Future&lt;ChildResponse&gt; childToken1 = asyncServ.runTransactionId("XXXX"); ChildResponse anyResponse = asyncServ.getAny(); if (anyResponse.equals(childToken1)) { msg = "Successfully fetched child token ";} else {msg = "Failed to fetched child token ";} 获取结果后,您可以继续使用 ChildResponse.getChannel(); 获取返回的 Channel 数据。
    猜你喜欢
    • 1970-01-01
    • 2012-02-21
    • 1970-01-01
    • 2021-06-21
    • 2018-02-13
    • 1970-01-01
    • 2013-05-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多