4

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

我知道在底层,ColdFusion 主要是 Java。所以我希望有办法。任何人都可以确认或否认这种可能性吗?有什么例子吗?

谢谢!

4

3 回答 3

3

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

因此,在看到这个问题之后,如果没有已知的方法来实现这一点,我开始思考一种可能的解决方法。假设在您的线程处理期间,它会测试应用程序/服务器/会话范围内的变量值。假设该值最初设置为“true”,然后被另一个进程设置为“false”,当线程找到错误值时,它可以优雅地终止。

于 2019-09-06T14:43:53.983 回答
2

你能?

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

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

由于本地名称可以被多个请求使用,所以引用应该存储在一个唯一的名称下,如 uuid。引用实际上是一个内部类的实例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()方法已被弃用,因为它本质上是不安全的

停止线程会导致它解锁所有已锁定的监视器。(当 ThreadDeath 异常向上传播堆栈时,监视器被解锁。)如果以前受这些监视器保护的任何对象处于不一致状态,则其他线程现在可能会查看这些处于不一致状态的对象。据说这些物体已损坏。当线程对损坏的对象进行操作时,可能会导致任意行为。这种行为可能很微妙且难以检测,也可能很明显。与其他未经检查的异常不同,ThreadDeath 以静默方式杀死线程;因此,用户没有警告他的程序可能已损坏。损坏可以在实际损坏发生后的任何时间出现,甚至在未来几小时或几天内。

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

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

于 2019-09-08T09:46:50.413 回答
2

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

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) />
于 2019-09-06T20:46:10.237 回答