Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/345.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java如何处理多线程中的错误?_Java_Multithreading_Error Handling - Fatal编程技术网

Java如何处理多线程中的错误?

Java如何处理多线程中的错误?,java,multithreading,error-handling,Java,Multithreading,Error Handling,我正在处理一个多线程项目,该项目中的线程可能会抛出错误(而不是异常)。由于没有找到关于多线程中如何处理错误的可靠信息,我决定做一些测试,结果可能不一致 这是我的测试代码,以及注释结果 public class MultiThreadError { public static class ErrorThrowingRunnable implements Runnable{ private final boolean throwsError; public E

我正在处理一个多线程项目,该项目中的
线程
可能会抛出
错误
(而不是
异常
)。由于没有找到关于多线程中如何处理错误的可靠信息,我决定做一些测试,结果可能不一致

这是我的测试代码,以及注释结果

public class MultiThreadError {
    public static class ErrorThrowingRunnable implements Runnable{
        private final boolean throwsError;
        public ErrorThrowingRunnable(boolean throwsError){
            this.throwsError = throwsError;
        }

        @Override
        public void run() {
            try {
                // Wait between .5 and 1.5 seconds
                Thread.sleep(500 + new Random().nextInt(1000));
            } catch (InterruptedException ex) {}
            if(throwsError){
                throw new Error(Thread.currentThread().getName());
            }else{
                System.out.println(Thread.currentThread().getName());
            }
        }
    }

    public static void regularThreadPool(){
        // Crashes individual thread; swallows error
        ExecutorService threadPool = Executors.newFixedThreadPool(5);
        threadPool.submit(new ErrorThrowingRunnable(false));
        threadPool.submit(new ErrorThrowingRunnable(false));
        threadPool.submit(new ErrorThrowingRunnable(false));
        threadPool.submit(new ErrorThrowingRunnable(false));
        threadPool.submit(new ErrorThrowingRunnable(true));
        threadPool.shutdown();
    }

    public static void onDemandThreads(){
        // Crashes individual thread; displays error
        new Thread(new ErrorThrowingRunnable(false)).start();
        new Thread(new ErrorThrowingRunnable(false)).start();
        new Thread(new ErrorThrowingRunnable(false)).start();
        new Thread(new ErrorThrowingRunnable(false)).start();
        new Thread(new ErrorThrowingRunnable(true)).start();
    }

    public static void onDemandThreadPool(){
        // Same as onDemandThreads()
        ExecutorService threadPool = Executors.newFixedThreadPool(5);
        threadPool.execute(new ErrorThrowingRunnable(false));
        threadPool.execute(new ErrorThrowingRunnable(false));
        threadPool.execute(new ErrorThrowingRunnable(false));
        threadPool.execute(new ErrorThrowingRunnable(false));
        threadPool.execute(new ErrorThrowingRunnable(true));
        threadPool.shutdown();
    }

    public static void tooSmallThreadPool(){
        // When an error is thrown, apparently the thread that threw
        // the error is not reused, reducing the pool size
        ExecutorService threadPool = Executors.newFixedThreadPool(3);
        threadPool.execute(new ErrorThrowingRunnable(true));
        threadPool.execute(new ErrorThrowingRunnable(false));
        threadPool.execute(new ErrorThrowingRunnable(false));
        threadPool.execute(new ErrorThrowingRunnable(false));
        threadPool.execute(new ErrorThrowingRunnable(false));
        threadPool.execute(new ErrorThrowingRunnable(false));
        threadPool.execute(new ErrorThrowingRunnable(false));
        threadPool.execute(new ErrorThrowingRunnable(false));
        threadPool.shutdown();
    }
}
似乎结果应该是我所期望的:抛出错误的线程终止,并显示消息。事实证明,当使用
submit(Runnable)
Runnable
传递给
ExecutorService
时,它被包装在一个不处理错误的
RunnableFuture
中,除了直接调用
execute(Runnable)
之外,我找不到改变这种行为的方法,由于某些原因,它不会表现出相同的行为


这方面有“最佳实践”吗?如果我知道某个线程可能会抛出错误,有没有办法
将其提交给ExecutorService而不接受错误?

是的,将任务提交给
ExecutorService
并在返回的
Future
中检查结果

使用时:

ExecutorService es = Executors.newFixedThreadPool(1);

Future<?> result = es.submit(new Runnable() {
    @Override
    public void run() {
        throw new Error("sample error");
    }
});

try {
    result.get();
} catch (ExecutionException e) {
    e.printStackTrace();
}

Future
是一个对象,它表示运行操作的结果,无论操作是现在准备好还是将来某个时候准备好。通常,人们会在所述的将来调用
get
方法以获得结果,特别是当您将
可调用的
而不是
可运行的
传递到
ExecutorService
中时

如果
Runnable
/
Callable
抛出异常,这将反映在
Future
对象中。您可以通过调用
get
方法来测试
Runnable
是否成功运行。如果这是一次干净的运行,您将(在本例中)返回
null
。如果抛出异常,则
get
将抛出
ExecutionException
,并将该异常标记为其原因


把它想象成音乐场所的外套支票。如果他们把你的外套弄丢了,他们可能不会告诉你,直到你拿着票来取外套。
未来的
在这里为您的票据服务。

试图处理从线程抛出的错误似乎是一个可疑的用例

来自Java文档:“错误是Throwable的一个子类,表示合理的应用程序不应尝试捕获的严重问题。大多数此类错误是异常情况。ThreadDeath错误虽然是“正常”情况,但也是错误的一个子类,因为大多数应用程序不应尝试捕获它。”


我唯一需要处理错误的时候是当我使用第三方时,他们管理异常很糟糕,抛出错误而不是RuntimeException。在这种特定情况下,您需要捕获错误(或可丢弃的错误),以避免意外的应用程序崩溃

在一个wee风格的注释中,您应该避免抛出
错误
。它们表示您无论如何都不应该尝试处理的严重问题(例如内存不足)。如果您希望从
Runnable
抛出某些内容,则应改用
RuntimeException
(或其子类)。的可能副本只是为了确保
RunnableFuture
可以很好地处理错误。所有可运行调用都包装在try/finally中。你的意思是说你看不到我怀疑的错误消息。如果它说抛出异常,你确定会捕获错误吗?@ndm13是的,它将是:“java.util.concurrent.ExecutionException:java.lang.error:sample error”。我已经更新了答案。@ndm13我已经更新了答案,在这里使用普通Runnable。可以在不使用throws声明的情况下从中抛出错误。通常我们使用
ExecutionException
getCause()
方法,这在javadocs中有解释。因此,从本质上讲,最佳实践是抛出RuntimeException并像处理任何其他异常一样处理它,即使通常会抛出错误,如果它在一个线程中?我个人找不到任何理由让你在代码中抛出错误。现在,如果您需要使用您不负责的代码,例如第三方,它会抛出错误,那么问题是:我是否应该捕获它。这是一个个案,但我想说的是,如果错误的原因是可恢复的,您可以捕获错误。例如,假设您的web应用程序使用第三方(如velocity),该第三方由于模板无效而引发错误,我认为您应该捕获并处理错误,因为web服务可以继续运行。
java.util.concurrent.ExecutionException: java.lang.Error: sample error
    at java.util.concurrent.FutureTask.report(Unknown Source)
    at java.util.concurrent.FutureTask.get(Unknown Source)
    at jjj.b.B.main(B.java:23)
Caused by: java.lang.Error: sample error
    at jjj.b.B$1.call(B.java:18)
    at jjj.b.B$1.call(B.java:1)
    at java.util.concurrent.FutureTask.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)