34

Java スレッドのrun()メソッドは、スレッドの開始時に、そのスレッドで JVM によって呼び出されます。スレッドに何かをさせるには、Thread のサブクラスを作成してその run() メソッドをオーバーライドするか、(推奨) スレッドのコンストラクターに Runnable を提供します。それはいいです。

Thread のサブクラスを作成して run をオーバーライドしている最中に、Thread.run() が public であるため、期待どおりにメソッドを保護できないことに気付きました。次に、その理由に気付きました。Thread は Runnable を実装しているため、公開する必要があります。しかし、なぜ Runnable を実装するのでしょうか?

論理的ではないようです。スレッドは(現在のスレッドから)開始可能ですが、(現在のスレッドから) Runnable を run() するのと同じ方法では実行しません。スレッド自体が(独自のスレッドで) 実行されます。Thread の run メソッドを手動で呼び出す場合は、それを Thread として使用するのではなく、重い Runnable として使用します。

設計上、Thread オブジェクトにアクセスできるコードはすべて、その public run メソッドを呼び出すことができ、公開することを意図していないコードや、そのように呼び出されるように設計されていないコードに突っ込む可能性があります。また、次のような非常に特殊なことも可能です。

Thread.currentThread.run();

私が見ていない Runnable を実装する Thread の正当な使用法はありますか?

4

2 に答える 2

27

その理由は「後方互換性」です。

このThreadクラスは、Java 1.0 ... 以前に作成されました。当時、Java には内部クラスがなかったため、Runnableインスタンスを実装するための軽量な方法はありませんでした。その時代の古いスレッドの例やチュートリアルを見ると、メソッドを拡張Threadしてオーバーライドするクラスがよく見られますrun()

時間の経過とともに、Thread(さまざまな理由から) 拡張は良い考えではないことがわかりました。ただし、Thread古い Java コードと新しい JVM との互換性がなくなるため、設計を変更することはできませんでした。


私が見ていない Runnable を実装する Thread の正当な使用法はありますか?

それは、「合法的」が何を意味するかによって異なります。

  • 初期の頃に書かれた古いコードは、昔ながらのやり方をしているので、「違法」ではありません。それについて「壊れた」ものは何もありません。

  • Thread を拡張してメソッドをオーバーライドすることが理にかなっているシナリオが潜在的run()に存在します。たとえばrun()、提供された との間で情報をやり取りするための特別なメカニズムを実装したり、Runnable特別な例外処理を実装したり、スレッドを「再起動可能」にしたりすることができます。

  • run()スレッド オブジェクトを直接呼び出したい場合もあります。たとえば、拡張された「犬の朝食」コードを渡された場合、元のコードを変更せずThreadにスレッドプールで実行するように変換する必要がありました。無愛想なスレッド クラスをインスタンス化し、そのインスタンスを実行可能なものとしてスレッドプールに渡して実行することを検討してください。(はい...恐ろしい!)

于 2013-08-19T03:30:17.597 に答える
4

run をオーバーライドしても、なぜ public にする必要があるのか​​説明できません。

これがあなたの問題である場合、それに対する簡単な答えがあると思います。インターフェースを実装するメソッドは、Java で常に public でなければなりません。抽象クラスで保護することは可能ですが、スレッドが抽象の場合、それをそのまま使用することはできません。

なぜ Thread が Runnable を最初に実装するのかというと、Java には、スレッドが実際にどの部分で仕事をしているのかを知る方法が必要です。そのために run メソッドを使用します。Runnable を実装するだけのロジックと Thread サブクラスにそれを実装させるロジックをより明確に分離できたはずですが、それは歴史的な理由から変更するのが難しい小さな間違いだと私は考えています。

TLDR; 私の知る限り、スレッドが Runnable を実装する正当な理由は実際にはありませんが、そのようなある種のインターフェースを実装する理由はあります。おそらく、同じものを使用する代わりに、ThreadRunnable のような何らかの分離されたインターフェースを持っていたはずです。他の用途にも使用できる実行可能なインターフェース。

また、最新の Java では、Threads の代わりに Callables と FutureTasks を使用する必要があることに注意してください。「タイムアウトの統合、適切なキャンセル、および最新の同時実行サポートのスレッド プーリングはすべて、生のスレッドの山よりもはるかに便利です。」、stackoverflow に関する別の回答を引用します。

于 2013-08-19T06:09:30.843 に答える