ColdFusion:在单独的请求中终止 CFTHREAD

ColdFusion : terminate CFTHREAD in separate request

我在我的 ColdFusion 应用程序中使用 CFTHREAD。根据我从 Ben Nadel (https://www.bennadel.com/blog/2980-terminating-asynchronous-cfthreads-in-coldfusion.htm) 那里读到的内容,ColdFusion 仅公开和跟踪当前请求中的线程。在我的情况下,我通过 ajax 调用生成一个线程,然后为用户提供一个取消按钮。我希望取消按钮可以调用线程上的终止方法,但无论我将它存储在哪里(应用程序、服务器、会话),ColdFusion 总是 returns 无法终止线程的错误 "THREAD_NAME"因为 "THREAD_NAME" 没有生成。

我知道在幕后,ColdFusion 主要是 Java。所以我希望有办法。谁能证实或否认这种可能性?任何例子如何?

谢谢!

抱歉,我没有 50 的评论评论,所以我会 post 这个作为答案。最近,我遇到了通过 ajax 生成的 CFThread 的相同情况,我需要以某种方式终止它但无法终止。我在 CFLoop 中有一个 CFQuery,它在应用程序范围内使用它的数据源。所以我想到的是登录 ColdFusion Administrator 并临时重命名导致线程抛出数据库错误的数据源。虽然这是不优雅的终止,但它在当时达到了目的。

因此,在看到这个问题后,我想到了一个可能的解决方法,如果没有已知的方法来完成这个。假设在您的线程处理期间,它测试 application/server/session 范围内的变量值。假设该值最初设置为 "true",随后被另一个进程设置为 "false",当线程发现错误值时,它可以正常终止。

您要做的是在应用程序或会话范围之类的地方设置一个数据结构,以跟踪您希望能够取消的线程 运行。

Application.cfc OnApplicationStart

<cfset application.cancelThread = {} />

在进入线程之前创建id然后传入线程

<cfset threadId = createUUID() />
<cfset application.cancelThread[threadId] = false />

将 threadId 传回客户端以用于取消按钮。点击取消按钮传回 threadId

<cfset application.cancelThread[form.threadId] = true />

线程执行期间

<cfif application.cancelThread[threadId]>
    <cfabort />
    <!--- or your chosen approach to ending the processing --->
</cfif>

如果线程到达末尾,则删除线程引用

<cfset structDelete(application.cancelThread, threadId) />

可以吗?

是,但仅使用内部 classes。创建 cfthread 时,使用本地 THREAD_NAME 检索对底层线程对象的引用。

context = getPageContext().getFusionContext();
thread = context.getUserThreadTask( "theLocalTaskName" );

由于本地名称可被多个请求使用,因此引用应存储在唯一名称下,如 uuid。该引用实际上是一个内部 class coldfusion.threads.Task 的实例。要终止它,调用它的 cancel() 方法。

thread.cancel();

你应该吗?

这是个大问题,一切都取决于线程做什么 - 它是如何做的 - 如果进程在没有警告的情况下中途停止,它使用的资源将如何受到影响。

原因是调用 <cfthread action="terminate"..> 会立即终止线程。 CF 不关心它是否在关键部分的中间。服务器只是用木槌敲打它并使其停止冷却。异常日志显示 CF 通过调用 Thread.stop()

来执行此操作
"Information","cfthread-47","09/07/19","17:10:44","","THREAD_V_2: Terminated"
java.lang.ThreadDeath
  at java.base/java.lang.Thread.stop(Thread.java:942)
  at coldfusion.thread.Task.cancel(Task.java:257)
  at coldfusion.tagext.lang.ThreadTag.terminateThread(ThreadTag.java:345)
  at coldfusion.tagext.lang.ThreadTag.doStartTag(ThreadTag.java:204)

java 文档说 stop() 方法已弃用,因为 it's inherently unsafe:

Stopping a thread causes it to unlock all the monitors that it has locked. (The monitors are unlocked as the ThreadDeath exception propagates up the stack.) If any of the objects previously protected by these monitors were in an inconsistent state, other threads may now view these objects in an inconsistent state. Such objects are said to be damaged. When threads operate on damaged objects, arbitrary behavior can result. This behavior may be subtle and difficult to detect, or it may be pronounced. Unlike other unchecked exceptions, ThreadDeath kills threads silently; thus, the user has no warning that his program may be corrupted. The corruption can manifest itself at any time after the actual damage occurs, even hours or days in the future.

因此,重要的是要考虑线程实际执行的操作,并确定终止它是否安全。例如,如果线程使用 FileOpen() 处理文件,强行终止它可能会阻止线程释放句柄,使底层文件处于锁定状态,这是不可取的。

在 java 中推荐的停止线程的方法是使用 interrupt()。这就是本质上的概念 。中断不会强制终止线程。它只是一个表明线程停止处理的标志。将其留给线程本身来确定何时可以安全退出。这允许线程在终止之前完成关键部分或执行任何清理任务。是的,它需要更多的编码,但结果比 "terminate".

更稳定和可预测