在 java/android 线程中替代长的、不可中断的方法

Alternative to long, non-interrumpible method in a java/android thread

在 Android 应用程序的 UI 线程中,我需要 运行 一个可能需要纳秒或永远完成的方法。我想我无法准确确定它会永远持续到什么时候,所以我 运行 通过池将它放在一个单独的线程中。

myPool = Executors.newCachedThreadPool(new ThreadFactory(){
    //override newThread(Runnable r)...
});

Future<Result> futureResult = myPool.submit(new Callable<Result>(){
    @Override public Result call(){
        return dangerousMethod();
    }
});

出于演示目的,我将 UI 暂停一秒钟,然后,如果该方法尚未完成,我将继续。

try{
    Result result = futureResult.get(1, TimeUnit.SECONDS);
    //Use result here
}catch(TimeoutException e) {//Other Exceptions are ommited
    futureResult.cancel(true);
    Log.d("DEMO", "Method takes too long. Skip");
}

我尝试取消 future 并用 futureResult.cancel(true) 中断它的线程,但是 dangerousMethod() 不会响应中断,所以线程将保持 运行ning 直到它最终完成任务。

我尝试过的方法:子类化 ThreadPoolExecutor 并通过反射 (Thread) 获取私有 Thread 以强制(Bad Practices TM) stop()(不工作,因为 UnsupportedOperationException)或 stop0()(也不工作,因为 NoSuchMethodException)。有关此的更多详细信息:

class MyPool extends ThreadPoolExecutor{
    //constructor, reflection code to get the Threads, etc

    void cancelThread(Thread thread){
        try {
            thread.stop();
        }catch(SecurityException | UnsupportedOperationException e) {
            try {
                Method stopMethod = Thread.class.getDeclaredMethod("stop0", Object.class);
                stopMethod.setAccessible(true);
                stopMethod.invoke(thread, new ThreadDeath());
            }catch(NoSuchMethodException | 
                   InvocationTargetException | 
                   IllegalAccessException x)
            {
                Log.d("MyPool", "Can't stop thread", x);
            }
        }
    }
}

危险的方法其实是这样的:

BigDecimal n1 = new BigDecimal("1E1000000");
BigDecimal n2 = new BigDecimal("1");
BigDecimal result = n1.add(n2);//Takes too long

我可以检查我使用的每个 BigDecimal 方法是否可以很好地处理数字,但我首先想知道我是否遗漏了一些明显的东西,或者还有另一种方法。因为

BigDecimal n3 = new BigDecimal("1E999999");
BigDecimal result = n1.add(n3);

效果不错。

您似乎无法强制终止 Android 中的 Java 线程 - 在 Oracle Java 中它实际上仍然有效。原因是在 Oracle Java stop() 中调用 stop1(),而在 Android 中它调用 stop(new ThreadDeath()),后者又无条件地抛出 UnsupportedOperationException.

但为什么要强迫它停止呢?就让它运行在后台吧,算了,继续。当然你有一些内存和 CPU 陷入困境的风险,但正如你所说只有一些数字导致方法 运行 那么长,所以你很可能会忘记这个线程并且能够成功启动其他大部分。

如果长 运行ning 后台线程在完成后尝试执行操作,您可以设置一个标志告诉他闭嘴。只要你不需要它的结果就很好。