在 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 后台线程在完成后尝试执行操作,您可以设置一个标志告诉他闭嘴。只要你不需要它的结果就很好。
在 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 后台线程在完成后尝试执行操作,您可以设置一个标志告诉他闭嘴。只要你不需要它的结果就很好。