终止正在运行本机代码的线程

dma*_*a_k 7 java multithreading

在我的应用程序中,我有一些本机代码的包装器,它通过JNI桥调用.此本机代码需要在单独的线程中执行(并行处理).但问题是代码有时会"挂起",因此线程需要"强制"终止.不幸的是我没有找到任何"微妙"的方法:一般建议是告诉线程中的代码优雅地退出,但我不能用这个本机代码(这是上面的第三方代码).

我使用Java Concurrent API进行任务提交:

Future<Integer> processFuture = taskExecutor.submit(callable);

try {
    result = processFuture.get(this.executionTimeout, TimeUnit.SECONDS).intValue();
}
catch (TimeoutException e) {
    // How to kill the thread here?
    throw new ExecutionTimeoutException("Execution timed out (max " + this.executionTimeout / 60 + "min)");
}
catch (...) {
    ... exception handling for other cases
}
Run Code Online (Sandbox Code Playgroud)

Future#cancel()只会中断线程,但不会终止它.所以我使用了以下技巧:

class DestroyableCallable implements Callable<Integer> {

    private Thread  workerThread;

    @Override
    public Integer call() {
        workerThread = Thread.currentThread();

        return Integer.valueOf(JniBridge.process(...));
    }

    public void stopWorkerThread() {
        if (workerThread != null) {
            workerThread.stop();
        }
    }
}

DestroyableCallable callable = new DestroyableCallable();

Future<Integer> processFuture = taskExecutor.submit(callable);

try {
    result = processFuture.get(this.executionTimeout, TimeUnit.SECONDS).intValue();
}
catch (TimeoutException e) {
    processFuture.cancel(true);
    // Dirty:
    callable.stopWorkerThread();

    ThreadPoolTaskExecutor threadPoolTaskExecutor = (ThreadPoolTaskExecutor) taskExecutor;

    logger.debug("poolSize: " + threadPoolTaskExecutor.getPoolSize() + ", maxPoolSize:"
                    + threadPoolTaskExecutor.getMaxPoolSize() + ", activeCount:"
                    + threadPoolTaskExecutor.getActiveCount());
    }

    throw new ...;
}
catch (...) {
    ... exception handling for other cases
}
Run Code Online (Sandbox Code Playgroud)

这段代码的问题/问题:

  • 一般来说这是正确的方法吗?还有其他更优雅的选择吗?
  • activeCount 任务执行程序没有减少,因此任务执行程序仍然"认为"该线程正在运行
  • 我不得不添加workerThread != nullcheck to stopWorkerThread()方法,因为这个变量null在某些情况下变成了.我无法理解这些案件是什么......

笔记:

  • 本机代码不使用文件描述符(套接字).一切都作为数据块传递给它,并以相同的方式返回.
  • 本机代码是CPU密集型的.即使它保证终止,也可能需要很长时间.

赏金编辑:重新访问本机代码的方法/建议很明确,请不要在回复中提供.我需要纯Java解决方案/解决方法.

Beg*_*moT 9

Java具有强制线程终止的纯选项.它是古老的,不推荐使用Thread.stop()(AFAIK).并且没有安全线程终止的选项(为什么.stop()被弃用,并且甚至不允许JVM实现者实现).

原因是应用程序内的所有线程共享内存和资源 - 因此,如果您在某个任意点强制终止线程,则无法确定终止线程未将某些共享内存/资源置于不一致状态.你甚至不能(通常)假设哪些资源(可能)是脏的('因为你不知道线程被停止的确切位置).

因此,如果您希望应用程序的某些线程能够中断,唯一的解决方案是在设计阶段提供"保存点"的一些表示法 - 目标线程代码中的位置,保证不会改变共享因此,线程退出此处是安全的.而且正是Thread.stop()javadocs告诉你的:安全地中断线程的唯一方法是设计线程的代码,这样它就可以自己响应某种中断请求.某种标志,由线程不时检查.

我试图告诉你:你不能做你被问及使用java线程/并发的事情.我建议你的方式(这是早在这里给出的)是在不同的过程中完成你的工作.强制终止进程比线程安全得多,因为1)进程彼此分离得多,2)OS在进程终止后负责许多清理.杀戮过程并不是完全安全的,因为存在某种资源(例如文件),默认情况下不会被操作系统清除,但在您的情况下它似乎是安全的.

所以你设计了一个小的独立应用程序(甚至可能在java中 - 如果你的第三方库没有提供其他绑定,甚至在shell脚本中),只有工作是让你计算.你从主应用程序开始这样的过程,给它工作,并启动看门狗.它看门狗检测到超时 - 它强行杀死进程.

这是唯一的解决方案草案.你可以实现某种进程池,如果你想提高性能(启动过程可能需要时间),等等......