5

スレッド化する場合は、スレッドを拡張するか、Javaでrunnableをマルチスレッドに実装できることを理解しています。しかし、なぜJavaからスレッドへのインターフェースを実装する必要があるのでしょうか。Javaスレッドを機能させる実行可能なインターフェースの重要性は何ですか?Javaのインターフェースは何かから拡張されていますか?

4

5 に答える 5

11

インターフェイスの唯一の特別な点は、コンストラクターを取り込む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それ自体はマルチスレッドとは何の関係もありません。これは、コードのブロックをオブジェクトにカプセル化するときに拡張する標準のインターフェイスにすぎません。

于 2012-10-19T01:15:06.400 に答える
2

機能面では、インターフェースの実装とクラスのRunnable拡張に違いはありません。Threadただし、インターフェースの実装Runnableが優先される場合があります。クラスが他のクラスから継承する必要があり、スレッド機能を表示する必要がある場合を考えてみてください。クラスは複数のクラスから継承できないため(Javaはサポートしていません)、Runnableその場合、クラスはインターフェイスを実装できます。

于 2012-10-19T01:14:55.073 に答える
2

しかし、なぜJavaからスレッドへのインターフェースを実装する必要があるのでしょうか。

前に述べたように、Threadオブジェクトを拡張して、publicvoidrunメソッドを実装することはできません。より組織的で柔軟な(はい、柔軟な)アプローチが必要な場合は、明らかな理由でRunnableを使用する必要があります。コードの再利用性です。

整理されていると言うとき、維持するのは簡単だと言いたいです

Runnable doSomething = new Runnable()
{
    @Override
    public void run()
    {
        goAndDoSomethingReallyHeavyWork();
    }
};

次に、同じランナブルを別のスレッドに再利用するか、同じスレッドを別の瞬間に再利用します(はい、実際にはスレッドを再利用できます)。2つ以上のスレッドを一度使用するオブジェクトに拡張します。

Javaスレッドを機能させる実行可能なインターフェースの重要性は何ですか?

重要なのは、Threadオブジェクトが、Runnableにメソッドが実行されていることを「認識」し、必要なときにそれを実行することです(したがって、停止、一時停止、およびその他のスレッドアクション)。

Javaのインターフェースは何かから拡張されていますか?

この質問はあなたにとって私の+1の価値があります。本当に知りたいのですが、これは言語の機能であり、Objectスーパークラスを拡張する他のすべてのオブジェクトのようなそれ自体の製品ではないようです。

お役に立てば幸いです。乾杯

于 2012-10-19T01:31:46.987 に答える
1

しかし、なぜJavaからスレッドへのインターフェースを実装する必要があるのでしょうか。

クラスThreadを拡張するスレッドを作成すると、他のクラスを拡張することはできなくなります(多重継承)。一方、Runnableを使用すると、必要に応じてクラスを拡張するという継承のメリットが得られます。

上記に加えて、メモリとパフォーマンスレベルのメリットも得られます。

于 2020-12-12T07:51:03.347 に答える
0

ExecutorService.submit​( Runnable task )

あなたが言った:

スレッドを拡張する

Threadコードを同時に実行するために、クラスを直接アドレス指定する必要がなくなりました。Java5はExecutorsフレームワークを導入しました。Oracleによるチュートリアルを参照してください。

エグゼキュータサービスは、1つ以上のバックグラウンドスレッドでのタスクの実行を管理します。Executorsクラスを介してインスタンス化された、いくつかのタイプのエグゼキュータサービスから選択できます。

時折いくつかの短期間のタスクの場合は、キャッシュされたスレッドプールに支えられたエグゼキュータサービスを使用します。

ExecutorService executorService = Executors.newCachedThreadPool();
executorService.submit( yourRunnableObjectGoesHere ) ;

の仕事は、正確にまたは。ExecutorServiceという名前のメソッドでコードを実行することです。runcall

他の正解が説明したように、Runnableインターフェースの目的はそれが契約を表すことです。あなたのコードがインターフェースを実装すると主張するときRunnable、あなたはあなたのコードが正確にという名前のメソッドを持っていることを約束していますrun

Javaコンパイラはこの約束に気づき、契約が履行されていることを確認します。Runnable(a)実装を宣言し(b)run引数を受け取らず、値を返さないメソッドを実行する両方に失敗したオブジェクトを渡すと、コンパイラはその状況をエラーとしてフラグ付けします。

Runnableしたがって、エグゼキュータサービスでは、タスクを(または)インターフェイスを実装するクラスのオブジェクトとして送信してCallable、タスクがバックグラウンドスレッドで実行されるように到着したときに、そのタスクに正確にrun(またはcallfor Callable)という名前のメソッドがあることを保証する必要があります。

サンプルコード

これがいくつかのサンプルコードです。エグゼキュータサービスが、メソッドに渡すオブジェクトの種類を気にしないことに注意してくださいsubmitDogクラス、、、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つのインターフェイスによって拡張されていることに注意してください。RunnableFutureRunnableScheduledFuture

于 2020-12-20T07:09:44.750 に答える