Java Exeutor框架的异常处理
我编写了一个android应用程序,用于杀死在后台线程中执行的后台运行进程。我使用下面的类来创建我自己的简单线程框架Java Exeutor框架的异常处理,java,android,multithreading,exception,Java,Android,Multithreading,Exception,我编写了一个android应用程序,用于杀死在后台线程中执行的后台运行进程。我使用下面的类来创建我自己的简单线程框架 public final class ThreadPool { private static final ExecutorService sES = Executors.newCachedThreadPool(); public static Future<?> runNow(Runnable task) { return sES.s
public final class ThreadPool {
private static final ExecutorService sES = Executors.newCachedThreadPool();
public static Future<?> runNow(Runnable task) {
return sES.submit(task);
}
}
但我仍然有以下问题:
如果使用submitRunnable命令方法,为什么Sun/Oracle决定使用异常而不是将异常传输给用户来处理?
如果我坚持使用submit方法,如何根据自己的需要更改此行为以处理未检查的异常?
我的疑问是:
如果使用submitRunnable命令方法,我知道可以通过Future.get方法获得异常结果。但是,如果我们使用Future.get方法来判断是否发生异常,则位于中的线程Future对象将被阻塞。我想,在大多数情况下,这不是我们所期望的。
我还学习了Executor.execute方法处理类似于common Thread.start的异常。但是没有返回值。因此,任务在任何时候都无法关闭。用户无法通过Future.cancel方法在离开活动时关闭任何正在运行的线程。
如果在将来调用get,如果基础操作callable抛出异常,则将得到ExecutionException
您无法从第1点更改此行为
这种方式实现的原因如下:submit是一个非阻塞调用。作业将在执行器中发布,并在稍后执行。
只有当作业被执行时,你才知道它是否崩溃,因此只有当你试图访问作业结果时,你才会得到异常。在线程化环境中,未经检查的异常被认为是臭名昭著的,并且会发生奇怪的行为,如线程死亡、没有异常日志等 一个好方法是将可运行对象包装在线程中。创建线程组并将线程添加到线程组
final ThreadGroup group = new ThreadGroup("<a name for the thread group>");
public static Future<?> submitNow(Runnable task) {
//Create a thread wrapping the runnable task and specify the thread group
Thread t = new Thread(group,task);
return sES.submit(task);
}
或者,您可以将UncaughtExceptionHandler分配给当前线程
public class MyUncaughtExceptionHandler implements UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread t, Throwable t2) {
//Implement
}
}
Thread.currentThread().setUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
或设置默认异常处理程序:
Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
最后,我找到了一个好的解决办法 我们可以在构造函数中扩展线程并调用setUncaughtHandler,如下所示
public class MyThread1 extends Thread {
public MyThread1(Runnable task) {
super(task);
setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("thread throws an uncaught exception at thread id: " + t.getId());
}
});
}
}
然后定制一个ThreadFactory,如下所示
public class MyThreadFactory1 implements ThreadFactory {
@Override
public Thread newThread(Runnable r) {
return new MyThread1(r, "Peace");
}
}
ExecutorService es = Executors.newSingleThreadExecutor(new MyThreadFactory1());
因此,我们可以在执行器中调用工厂方法,如下所示
public class MyThreadFactory1 implements ThreadFactory {
@Override
public Thread newThread(Runnable r) {
return new MyThread1(r, "Peace");
}
}
ExecutorService es = Executors.newSingleThreadExecutor(new MyThreadFactory1());
因此,我们可以检测线程中发生的未捕获异常。您知道try/catch块吗?@immibis当然知道。那么您有什么建议吗?那么您就知道如何在没有线程的情况下运行Runnable并捕获异常。你可以在另一条线上做,是的。我现在在每个run方法中使用该方法。但是它会带来一些重复编码。try{otherRunnable.run;}catchException e{/*做点什么*/}你知道SUN/ORACLE为什么在Executor框架中以这种方式处理异常吗?它有什么好处吗?我认为如果未检查的异常被安静地消费是不好的。添加了一个简单的解释,解释为什么这样实现。这有一定的意义。但默认行为至少应将异常堆栈跟踪打印到控制台。然而,当事情发生时,它什么也没有显示。为什么?不处理异常,向控制台进行简单打印意味着处理异常。我的意思是,无论如何,你都必须以线程安全的方式访问后台操作的结果,所以你还是要调用get。显然,线程池因为其缺陷而被弃用。@你说的线程池被弃用是什么意思?请至少提供一个链接来证明你对弃用的评论。您所指的具体缺陷是什么?我也没有提到ThreadPool,但我提到了ThreadGroup.1。很抱歉使用了错误的单词ThreadPool。它应该是ThreadGroup。2.下面是您提供的web的第一句话:ThreadGroup是一种将线程组织成层次结构的方法。这个类已经过时了。有关详细信息,请参见有效Java项目73,避免线程组。链接是:@peacepassion-它被认为是过时的,但并没有正式弃用。忘了ThreadGroup吧,我的最后一个建议仍然适用于有效的Java 73:在1.5版之前,只有ThreadGroup API提供了一小部分功能:ThreadGroup.uncaughtException方法是在线程引发未捕获异常时获得控制的唯一方法。例如,此功能对于将堆栈跟踪定向到特定于应用程序的日志非常有用。但是,从1.5版开始,线程的setUncaughtExceptionHandler方法就提供了相同的功能。