スレッド化する場合は、スレッドを拡張するか、Javaでrunnableをマルチスレッドに実装できることを理解しています。しかし、なぜJavaからスレッドへのインターフェースを実装する必要があるのでしょうか。Javaスレッドを機能させる実行可能なインターフェースの重要性は何ですか?Javaのインターフェースは何かから拡張されていますか?
5 に答える
インターフェイスの唯一の特別な点は、コンストラクターを取り込むRunnable
ことです。Thread
それは単なる古いインターフェースです。
ほとんどのインターフェースと同様に、重要なのは、コントラクトにプログラミングしているということです。実行するコードをRunnable#run()
実装に配置Thread
することに同意し、そのコードを別のスレッドで実行することに同意します(コードを作成して開始するThread
とき) 。 。
それThread
は実際にマルチスレッドを「実行」します(ネイティブシステムと相互作用するという点で)。の実装は、実行Runnable
するように指示するコードを配置する場所ですThread
。
実際、Runnable
別のスレッドで実行しなくても、を実装して実行できます。
Runnable someCode = new Runnable() {
public void run() {
System.out.println("I'm a runnable");
}
};
someCode.run();
したがって、Runnable
それ自体はマルチスレッドとは何の関係もありません。これは、コードのブロックをオブジェクトにカプセル化するときに拡張する標準のインターフェイスにすぎません。
機能面では、インターフェースの実装とクラスのRunnable
拡張に違いはありません。Thread
ただし、インターフェースの実装Runnable
が優先される場合があります。クラスが他のクラスから継承する必要があり、スレッド機能を表示する必要がある場合を考えてみてください。クラスは複数のクラスから継承できないため(Javaはサポートしていません)、Runnable
その場合、クラスはインターフェイスを実装できます。
しかし、なぜJavaからスレッドへのインターフェースを実装する必要があるのでしょうか。
前に述べたように、Threadオブジェクトを拡張して、publicvoidrunメソッドを実装することはできません。より組織的で柔軟な(はい、柔軟な)アプローチが必要な場合は、明らかな理由でRunnableを使用する必要があります。コードの再利用性です。
整理されていると言うとき、維持するのは簡単だと言いたいです
Runnable doSomething = new Runnable()
{
@Override
public void run()
{
goAndDoSomethingReallyHeavyWork();
}
};
次に、同じランナブルを別のスレッドに再利用するか、同じスレッドを別の瞬間に再利用します(はい、実際にはスレッドを再利用できます)。2つ以上のスレッドを一度使用するオブジェクトに拡張します。
Javaスレッドを機能させる実行可能なインターフェースの重要性は何ですか?
重要なのは、Threadオブジェクトが、Runnableにメソッドが実行されていることを「認識」し、必要なときにそれを実行することです(したがって、停止、一時停止、およびその他のスレッドアクション)。
Javaのインターフェースは何かから拡張されていますか?
この質問はあなたにとって私の+1の価値があります。本当に知りたいのですが、これは言語の機能であり、Objectスーパークラスを拡張する他のすべてのオブジェクトのようなそれ自体の製品ではないようです。
お役に立てば幸いです。乾杯
しかし、なぜJavaからスレッドへのインターフェースを実装する必要があるのでしょうか。
クラスThreadを拡張するスレッドを作成すると、他のクラスを拡張することはできなくなります(多重継承)。一方、Runnableを使用すると、必要に応じてクラスを拡張するという継承のメリットが得られます。
上記に加えて、メモリとパフォーマンスレベルのメリットも得られます。
ExecutorService.submit( Runnable task )
あなたが言った:
スレッドを拡張する
Thread
コードを同時に実行するために、クラスを直接アドレス指定する必要がなくなりました。Java5はExecutorsフレームワークを導入しました。Oracleによるチュートリアルを参照してください。
エグゼキュータサービスは、1つ以上のバックグラウンドスレッドでのタスクの実行を管理します。Executors
クラスを介してインスタンス化された、いくつかのタイプのエグゼキュータサービスから選択できます。
時折いくつかの短期間のタスクの場合は、キャッシュされたスレッドプールに支えられたエグゼキュータサービスを使用します。
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.submit( yourRunnableObjectGoesHere ) ;
の仕事は、正確にまたは。ExecutorService
という名前のメソッドでコードを実行することです。run
call
他の正解が説明したように、Runnable
インターフェースの目的はそれが契約を表すことです。あなたのコードがインターフェースを実装すると主張するときRunnable
、あなたはあなたのコードが正確にという名前のメソッドを持っていることを約束していますrun
。
Javaコンパイラはこの約束に気づき、契約が履行されていることを確認します。Runnable
(a)実装を宣言し、(b)run
引数を受け取らず、値を返さないメソッドを実行する両方に失敗したオブジェクトを渡すと、コンパイラはその状況をエラーとしてフラグ付けします。
Runnable
したがって、エグゼキュータサービスでは、タスクを(または)インターフェイスを実装するクラスのオブジェクトとして送信してCallable
、タスクがバックグラウンドスレッドで実行されるように到着したときに、そのタスクに正確にrun
(またはcall
for Callable
)という名前のメソッドがあることを保証する必要があります。
サンプルコード
これがいくつかのサンプルコードです。エグゼキュータサービスが、メソッドに渡すオブジェクトの種類を気にしないことに注意してくださいsubmit
。Dog
クラス、、、SalesReport
またはのオブジェクトを渡すことができますPayroll
—重要ではありません。エグゼキュータサービスが気にするのは、渡されるオブジェクトに。submit
というメソッドがあることだけrun
です。
package work.basil.example;
import java.time.Duration;
import java.time.Instant;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Demo
{
public static void main ( String[] args )
{
Demo app = new Demo();
app.demo();
}
private void demo ( )
{
Runnable task = new Runnable()
{
@Override
public void run ( )
{
System.out.println( "Doing this work on a background thread. " + Instant.now() );
}
};
ExecutorService executorService = null;
try
{
executorService = Executors.newCachedThreadPool();
executorService.submit( task );
executorService.submit( task );
executorService.submit( task );
// Wait a moment for the background threads to do their work.
try
{
Thread.sleep( Duration.ofSeconds( 2 ).toMillis() );
}
catch ( InterruptedException e )
{
e.printStackTrace();
}
}
finally
{
if ( Objects.nonNull( executorService ) ) { executorService.shutdown(); }
System.out.println( "Ending the main thread. " + Instant.now() );
}
}
}
実行時:
Doing this work on a background thread. 2020-12-20T07:16:26.119414Z
Doing this work on a background thread. 2020-12-20T07:16:26.119176Z
Doing this work on a background thread. 2020-12-20T07:16:26.119255Z
Ending the main thread. 2020-12-20T07:16:28.124384Z
ラムダ構文
最新のJavaのラムダ構文に慣れている場合は、Runnable
実装を定義するコードを1行に短縮できます。同じ効果ですが、構文が異なります。
package work.basil.example;
import java.time.Duration;
import java.time.Instant;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Demo
{
public static void main ( String[] args )
{
Demo app = new Demo();
app.demo();
}
private void demo ( )
{
Runnable task = ( ) -> System.out.println( "Doing this work on a background thread. " + Instant.now() );
ExecutorService executorService = null;
try
{
executorService = Executors.newCachedThreadPool();
executorService.submit( task );
executorService.submit( task );
executorService.submit( task );
// Wait a moment for the background threads to do their work.
try
{
Thread.sleep( Duration.ofSeconds( 2 ).toMillis() );
}
catch ( InterruptedException e )
{
e.printStackTrace();
}
}
finally
{
if ( Objects.nonNull( executorService ) ) { executorService.shutdown(); }
System.out.println( "Ending the main thread. " + Instant.now() );
}
}
}
継承
あなたは尋ねました:
Javaのインターフェースは何かから拡張されていますか?
Javaのすべてのクラスは、Object
クラスまたはから拡張する他のクラスのいずれかを拡張しObject
ます。
Javaのインターフェースは、どのクラスからも拡張されていません。インターフェイスは単なるコントラクトであり、特定のタイプの引数を取り、特定のタイプの値を返す特定の名前のメソッドを持つことに関して、一部のクラスが選択する可能性があることを忘れないでください。
Javaのインターフェースは、1つ以上の他のインターフェースを拡張できます。そうすることで、そのインターフェースを実装すると主張するクラスによって行われる約束にさらにメソッドが追加されます。とは、Runnable
他の2つのインターフェイスによって拡張されていることに注意してください。RunnableFuture
RunnableScheduledFuture