43

ねえ、私はいくつかのカスタムバイナリ形式のパケットを読み取るネットワークアプリケーションを書いています。そして、受信データを待つためにバックグラウンドスレッドを開始しています。問題は、コンパイラーが(チェックされた)例外をスローするコードをに入れさせないことですrun()。それは言う:

run()in(...)。Listenerは、run()をjava.lang.Runnableに実装できません。オーバーライドされたメソッドはjava.io.IOExceptionをスローしません

例外でスレッドを強制終了し、親スレッドのどこかでキャッチできるようにします。これを達成することは可能ですか、それともスレッドのすべての例外を処理する必要がありますか?

4

10 に答える 10

50

例外を親スレッドに送信できるようにするには、バックグラウンド スレッドをCallableに配置して(チェック済みの例外もスローできるようにします)、それを一部の Executorのsubmitメソッドに渡します。submit メソッドは、例外を取得するために使用できるFutureを返します (そのgetメソッドは、元の例外を含むExecutionExceptionをスローします)。

于 2009-09-02T20:19:38.510 に答える
42

警告: 例外メカニズムを使用する必要がある場合、これはニーズを満たさない可能性があります。

私があなたを正しく理解していれば、実際には例外をチェックする必要はありません (チェックされていない例外を示唆する回答を受け入れました) ので、単純なリスナーパターンの方が適切でしょうか?

リスナーは親スレッドに存在する可能性があり、子スレッドでチェック例外をキャッチしたら、リスナーに通知するだけです。

これは、(パブリック メソッドを介して) これが発生することを公開する方法があり、例外が許可するよりも多くの情報を渡すことができることを意味します。しかし、これは、親スレッドと子スレッドの間に (緩いものではありますが) 結合があることを意味します。これがチェックされた例外をチェックされていない例外でラップするよりも利点があるかどうかは、特定の状況によって異なります。

簡単な例を次に示します(別の回答から借用したコードもあります):

public class ThingRunnable implements Runnable {
    private SomeListenerType listener;
    // assign listener somewhere

    public void run() {
        try {
            while(iHaveMorePackets()) { 
                doStuffWithPacket();
            }
        } catch(Exception e) {
            listener.notifyThatDarnedExceptionHappened(...);
        }
    }
 }

カップリングは、親スレッド内のオブジェクトのタイプである必要がありSomeListenerTypeます。

于 2009-09-02T20:03:57.107 に答える
37

この回答は Esko Luontola one に基づいていますが、実際の例を提供しています。

Runnable インターフェースの run() メソッドとは異なり、Callable の call() メソッドではいくつかの例外をスローできます。実装例は次のとおりです。

public class MyTask implements Callable<Integer> {

    private int numerator;
    private int denominator;

    public MyTask(int n, int d) {
        this.numerator = n;
        this.denominator = d;
    }

    @Override
    // The call method may throw an exception
    public Integer call() throws Exception {
        Thread.sleep(1000);
        if (denominator == 0) {
            throw new Exception("cannot devide by zero");
        } else {
            return numerator / denominator;
        }
    }

}

Executor は、スレッド内で Callable を実行し、あらゆる種類の例外を処理するメカニズムを提供します。

public class Main {

    public static void main(String[] args) {

        // Build a task and an executor
        MyTask task = new MyTask(2, 0);
        ExecutorService threadExecutor = Executors.newSingleThreadExecutor();

        try {
            // Start task on another thread
            Future<Integer> futureResult = threadExecutor.submit(task);

            // While task is running you can do asynchronous operations
            System.out.println("Something that doesn't need the tasks result");

            // Now wait until the result is available
            int result = futureResult.get();
            System.out.println("The result is " + result);
        } catch (ExecutionException e) {
            // Handle the exception thrown by the child thread
            if (e.getMessage().contains("cannot devide by zero"))
                System.out.println("error in child thread caused by zero division");
        } catch (InterruptedException e) {
            // This exception is thrown if the child thread is interrupted.
            e.printStackTrace();
        }
    }
}
于 2011-09-24T13:24:11.103 に答える
7

私がしていることは、スレッドで例外をキャッチし、それを Runnable のメンバー変数として格納することです。この例外は、Runnable の getter を介して公開されます。次に、親からのすべてのスレッドをスキャンして、例外があるかどうかを確認し、適切なアクションを実行します。

于 2009-09-02T19:37:45.287 に答える
5

例外が発生したときに本当に何もできない場合は、チェックされた例外を RuntimeException でラップできます。

try {
    // stuff
} catch (CheckedException yourCheckedException) {
    throw new RuntimeException("Something to explain what is happening", yourCheckedException);
}
于 2009-09-02T18:03:03.903 に答える
3

スレッドは、他のスレッド (またはメイン スレッド) に例外をスローできません。また、継承された run() メソッドにチェック例外をスローさせることはできません。これは、継承されたコードよりも少ない数しかスローできず、それ以上はスローできないためです。

于 2009-09-02T18:06:09.483 に答える
1

スレッドのコードが RuntimeExpection をスローする場合、run() throw Exception を追加する必要はありません。

ただし、これは不適切な方法になる可能性があるため、適切な場合にのみこのソリューションを使用してください

任意の RuntimeException または unchecked Exception が役立ちます。独自の RuntimeException を作成する必要があるかもしれません

于 2009-09-02T18:05:46.613 に答える
0

コードがある種のループにあると仮定すると、次のように記述します。

public class ThingRunnable implements Runnable {
  public void run() {
    try {
      while(iHaveMorePackets()) { 
        doStuffWithPacket()
      }
    } catch(Exception e) {
      System.out.println("Runnable terminating with exception" + e );
    }
  }
}

例外により、自動的にループから抜け出し、run() メソッドの最後でスレッドが停止します。

于 2009-09-02T18:10:06.073 に答える
-1

例外を a 内にラップするRuntimeExceptionと、うまくいくようです。

someMethod() throws IOException
{
    try
    {
        new Thread(() ->
        {
            try
            {
                throw new IOException("a checked exception thrown from within a running thread");
            }
            catch(IOException ex)
            {
                throw new RuntimeException("a wrapper exception", ex); // wrap the checked exception inside an unchecked exception and throw it
            }
        }).start();
    }
    catch(RuntimeException ex) // catch the wrapped exception sent from within the thread
    {
        if(ex.getCause() instanceof IOException)
            throw ex.getCause; // unwrap the checked exception using getCause method and use it however you need
        else
            throw ex;
    }
}
于 2016-04-18T07:33:34.630 に答える