2277

でスレッドを使用してきた時間から、スレッドJavaを記述する次の 2 つの方法を見つけました。

道具を使ってRunnable

public class MyRunnable implements Runnable {
    public void run() {
        //Code
    }
}
//Started with a "new Thread(new MyRunnable()).start()" call

または、extendsでThread:

public class MyThread extends Thread {
    public MyThread() {
        super("MyThread");
    }
    public void run() {
        //Code
    }
}
//Started with a "new MyThread().start()" call

これら 2 つのコード ブロックに大きな違いはありますか?

4

43 に答える 43

1777

はい: RunnableIMO では、implements が推奨される方法です。スレッドの動作を本当に専門化していません。あなたはそれに実行する何かを与えているだけです。つまり、構成哲学的に「より純粋な」方法です。

実際にはRunnable、別のクラスからも実装および拡張できることを意味します...またRunnable、Java 8 のラムダ式を介して実装することもできます。

于 2009-02-12T14:32:54.340 に答える
604

tl;dr: Runnable を実装する方が優れています。ただし注意点は重要

一般に、選択した同時実行性と疎結合で作業を維持できるためでRunnableはなく、ようなものを使用することをお勧めします。Threadたとえば、 a を使用し、Runnable後でこれが実際には独自の を必要としないと判断したThread場合は、単に threadA.run() を呼び出すことができます。

警告:ここでは、未加工のスレッドの使用を強くお勧めしません。私はCallablesFutureTasksの使用を非常に好みます(javadoc から: 「キャンセル可能な非同期計算」)。タイムアウトの統合、適切なキャンセル、および最新の同時実行サポートのスレッド プーリングはすべて、生のスレッドの山よりもはるかに便利です。

フォローアップ: Runnables を使用できるようにするFutureTaskコンストラクターがあり(それが最も使い慣れている場合)、それでも最新の同時実行ツールの利点を得ることができます。 javadoc を引用するには:

特定の結果が必要ない場合は、次の形式の構造を使用することを検討してください。

Future<?> f = new FutureTask<Object>(runnable, null)

したがって、 theirrunnableを yourthreadAに置き換えると、次のようになります。

new FutureTask<Object>(threadA, null)

Runnables に近づけるためのもう 1 つのオプションは、ThreadPoolExecutorです。executeメソッドを使用して Runnable を渡し、「将来のある時点で指定されたタスク」を実行できます。

スレッド プールを使用したい場合、上記のコード フラグメントは次のようになります ( Executors.newCachedThreadPool()ファクトリ メソッドを使用)。

ExecutorService es = Executors.newCachedThreadPool();
es.execute(new ThreadA());
于 2009-02-12T14:37:05.390 に答える
281

この話の教訓:

一部の動作をオーバーライドする場合にのみ継承します。

または、次のように読む必要があります。

継承を減らし、インターフェイスを強化します。

于 2010-03-11T15:50:54.523 に答える
266

非常に多くの良い回答があるので、これについてさらに追加したいと思います。これは理解するのに役立ちますExtending v/s Implementing Thread
拡張は 2 つのクラス ファイルを非常に密接にバインドするため、コードの処理がかなり困難になる場合があります。

どちらのアプローチも同じ働きをしますが、いくつかの違いがあります。
最も一般的な違いは、

  1. Thread クラスを拡張すると、その後、必要な他のクラスを拡張することはできません。(ご存知のように、Java では複数のクラスを継承できません)。
  2. Runnable を実装すると、クラスのスペースを節約して、将来または現在他のクラスを拡張できます。

ただし、Runnable の実装と Thread の拡張の大きな違いの 1 つは、
by extending Thread, each of your threads has a unique object associated with it, whereas implementing Runnable, many threads can share the same object instance.

次の例は、より明確に理解するのに役立ちます

//Implement Runnable Interface...
class ImplementsRunnable implements Runnable {

    private int counter = 0;

    public void run() {
        counter++;
        System.out.println("ImplementsRunnable : Counter : " + counter);
    }
}

//Extend Thread class...
class ExtendsThread extends Thread {

    private int counter = 0;

    public void run() {
        counter++;
        System.out.println("ExtendsThread : Counter : " + counter);
    }
}
    
//Use the above classes here in main to understand the differences more clearly...
public class ThreadVsRunnable {

    public static void main(String args[]) throws Exception {
        // Multiple threads share the same object.
        ImplementsRunnable rc = new ImplementsRunnable();
        Thread t1 = new Thread(rc);
        t1.start();
        Thread.sleep(1000); // Waiting for 1 second before starting next thread
        Thread t2 = new Thread(rc);
        t2.start();
        Thread.sleep(1000); // Waiting for 1 second before starting next thread
        Thread t3 = new Thread(rc);
        t3.start();

        // Creating new instance for every thread access.
        ExtendsThread tc1 = new ExtendsThread();
        tc1.start();
        Thread.sleep(1000); // Waiting for 1 second before starting next thread
        ExtendsThread tc2 = new ExtendsThread();
        tc2.start();
        Thread.sleep(1000); // Waiting for 1 second before starting next thread
        ExtendsThread tc3 = new ExtendsThread();
        tc3.start();
    }
}

上記プログラムの出力。

ImplementsRunnable : Counter : 1
ImplementsRunnable : Counter : 2
ImplementsRunnable : Counter : 3
ExtendsThread : Counter : 1
ExtendsThread : Counter : 1
ExtendsThread : Counter : 1

Runnable インターフェイス アプローチでは、クラスのインスタンスが 1 つだけ作成され、異なるスレッドによって共有されています。したがって、カウンターの値は、スレッドアクセスごとにインクリメントされます。

一方、スレッド クラスのアプローチでは、スレッド アクセスごとに個別のインスタンスを作成する必要があります。したがって、クラス インスタンスごとに異なるメモリが割り当てられ、それぞれに個別のカウンターがあり、値は同じままです。つまり、同じオブジェクト参照がないため、インクリメントは発生しません。

いつランナブルを使用するのですか?
スレッドのグループから同じリソースにアクセスする場合は、Runnable インターフェイスを使用します。ここで Thread クラスを使用しないでください。複数のオブジェクトを作成すると、より多くのメモリが消費され、パフォーマンスのオーバーヘッドが大きくなります。

Runnable を実装するクラスはスレッドではなく、単なるクラスです。Runnable が Thread になるには、Thread のインスタンスを作成し、それ自体をターゲットとして渡す必要があります。

run()ほとんどの場合、メソッドをオーバーライドするだけで、他の Thread メソッドをオーバーライドしない場合は、Runnable インターフェイスを使用する必要があります。プログラマーがクラスの基本的な動作を変更または強化するつもりでない限り、クラスをサブクラス化するべきではないため、これは重要です。

スーパークラスを拡張する必要がある場合は、Thread クラスを使用するよりも Runnable インターフェースを実装する方が適切です。Runnable インターフェイスを実装してスレッドを作成しながら、別のクラスを拡張できるためです。

これが役立つことを願っています!

于 2013-03-05T14:26:04.950 に答える
86

まだ言及されていないことに驚いたのは、実装Runnableするとクラスがより柔軟になるということです。

スレッドを拡張すると、実行中のアクションは常にスレッドになります。ただし、実装Runnableする場合は、そうである必要はありません。スレッドで実行するか、何らかのエグゼキュータ サービスに渡すか、単一のスレッド アプリケーション内のタスクとして渡すことができます (後で実行することもできますが、同じスレッド内で実行することもできます)。Runnableに自分自身をバインドする場合よりも、使用するだけの場合、オプションははるかにオープンですThread

于 2009-02-12T14:51:35.123 に答える
83

他のクラスを実装または拡張したい場合は、Runnableインターフェースが最も望ましいです。それ以外の場合、他のクラスを拡張または実装したくない場合は、Threadクラスが望ましいです。

最も一般的な違いは、

ここに画像の説明を入力

クラスを作成するextends Threadと、その後、必要な他のクラスを拡張することはできません。(ご存知のように、Java では複数のクラスを継承できません)。

するとimplements Runnable、クラスのスペースを節約して、将来または現在他のクラスを拡張できます。

  • Java は複数の継承をサポートしていません。つまり、Java では 1 つのクラスしか拡張できないため、Thread クラスを拡張するとチャンスが失われ、Java で別のクラスを拡張または継承することはできません。

  • オブジェクト指向プログラミングでは、クラスの拡張は通常、新しい機能を追加し、動作を変更または改善することを意味します。Thread に変更を加えていない場合は、代わりに Runnable インターフェイスを使用してください。

  • Runnable インターフェイスは、プレーン スレッドまたはエグゼキュータまたはその他の手段で実行できる Task を表します。そのため、スレッドよりも実行可能としてタスクを論理的に分離することは、適切な設計上の決定です。

  • タスクを Runnable として分離することは、タスクを再利用できることを意味し、さまざまな手段からタスクを実行する自由もあります。スレッドが完了すると、スレッドを再開できないためです。再び Runnable とタスクのスレッド、Runnable が勝者です。

  • Java デザイナーはこれを認識しているため、Executor は Runnable を Task として受け入れ、それらのタスクを実行するワーカー スレッドを持っています。

  • すべての Thread メソッドを継承することは、Runnable で簡単に実行できる Task を表すためだけの追加のオーバーヘッドです。

javarevisited.blogspot.comからの礼儀

これらは、Java の Thread と Runnable の顕著な違いの一部です。Thread と Runnable のその他の違いを知っている場合は、コメントで共有してください。私は個人的にこのシナリオで Runnable over Thread を使用しており、要件に基づいて Runnable または Callable インターフェイスを使用することをお勧めします。

ただし、重要な違いは次のとおりです。

クラスをextends Thread作成すると、各スレッドが一意のオブジェクトを作成して関連付けます。するとimplements Runnable、同じオブジェクトを複数のスレッドで共有します。

于 2013-05-11T08:59:42.730 に答える
46

Runnable を実装する必要がありますが、Java 5 以降で実行している場合は、それを開始するのではなく、代わりにExecutorServicenew Threadを使用する必要があります。詳細については、「 Java で単純なスレッドを実装する方法」を参照してください。

于 2009-02-12T14:41:22.293 に答える
35

私は専門家ではありませんが、Thread を拡張する代わりに Runnable を実装する 1 つの理由を考えることができます。Java は単一継承のみをサポートするため、拡張できるクラスは 1 つだけです。

編集:これはもともと「インターフェースの実装に必要なリソースが少ない」と言っていました。同様に、どちらの方法でも新しい Thread インスタンスを作成する必要があるため、これは間違っていました。

于 2009-02-12T14:32:01.487 に答える
21

3番目の方法があると思います:

public class Something {

    public void justAnotherMethod() { ... }

}

new Thread(new Runnable() {
   public void run() {
    instanceOfSomething.justAnotherMethod();
   }
}).start();

おそらくこれは、私の最近の Javascript と Actionscript 3 の多用に少し影響を受けているのかもしれませんが、この方法では、クラスでRunnable.

于 2010-10-25T21:41:00.943 に答える
19

Java 8 のリリースにより、3 番目のオプションが追加されました。

Runnableこれは、そのインスタンスをラムダ式またはメソッド参照で作成できることを意味します

あなたの例は次のものに置き換えることができます:

new Thread(() -> { /* Code here */ }).start()

ExecutorServiceまたは、およびメソッド参照を使用する場合:

executor.execute(runner::run)

これらはあなたの例よりもはるかに短いだけでなく、スレッドの動作を専門化していないため、単一の責任や構成の使用など、Runnableoverを使用する他の回答で述べられている利点の多くも付属しています。Threadこの方法では、例で行っているように必要なものが a だけである場合、余分なクラスを作成することも回避できRunnableます。

于 2014-07-29T11:24:56.603 に答える
18

インターフェイスをインスタンス化すると、コードとスレッドの実装が明確に分離されるため、この場合は Runnable を実装することをお勧めします。

于 2009-02-12T14:33:09.207 に答える
13

ここにいる誰もが、Runnable の実装が進むべき道であると考えているようで、私は彼らにまったく同意しませんが、私の意見では Thread を拡張するケースもあります。実際、コードでそれを実証しています。

Runnable を実装する場合、Runnable を実装するクラスはスレッド名を制御できません。次のように、スレッド名を設定できるのは呼び出しコードです。

new Thread(myRunnable,"WhateverNameiFeelLike");

ただし、Thread を拡張すると、クラス自体の中でこれを管理できます (例のように、スレッドに「ThreadB」という名前を付けます)。この場合、次のことを行います。

A)デバッグ目的でより便利な名前を付ける可能性があります

B)その名前がそのクラスのすべてのインスタンスに使用されることを強制しています(それがスレッドであるという事実を無視し、Runnableであるかのように上記を実行しない限り、ここで慣習について話しているので、いずれにしてもそうすることができます私が感じるその可能性を無視してください)。

たとえば、その作成のスタック トレースを取得し、それをスレッド名として使用することもできます。これは奇妙に思えるかもしれませんが、コードの構造によっては、デバッグ目的で非常に役立つ場合があります。

これは小さなことのように思えるかもしれませんが、多くのスレッドを含む非常に複雑なアプリケーションがあり、すべてが突然「停止」した場合 (デッドロックの理由か、ネットワーク プロトコルの欠陥が原因である可能性があります)。明白な - または他の無限の理由) すべてのスレッドが 'Thread-1'、'Thread-2'、'Thread-3' と呼ばれる Java からスタック ダンプを取得することは、常に非常に役立つとは限りません (スレッドの状態によって異なります)。構造化されており、スタックトレースだけでどれがどれであるかを便利に判断できるかどうか-同じコードをすべて実行している複数のスレッドのグループを使用している場合は常に可能であるとは限りません)。

もちろん、その名前をその作成呼び出しのスタックトレースに設定するスレッドクラスの拡張を作成し、それを標準の Java Thread クラスの代わりに Runnable 実装で使用することにより、上記を一般的な方法で行うこともできます。 (以下を参照)しかし、スタックトレースに加えて、デバッグ用のスレッド名に役立つコンテキスト固有の情報がさらにある可能性があります(たとえば、処理できる多くのキューまたはソケットの1つへの参照。その場合に特にスレッドを拡張して、名前で使用するために特定の情報(たとえば、問題のキュー/ソケット)を渡すようにコンパイラーに強制させることができます)。

呼び出し元のスタック トレースを名前として持つ汎用スレッドの例を次に示します。

public class DebuggableThread extends Thread {
    private static String getStackTrace(String name) {
        Throwable t= new Throwable("DebuggableThread-"+name);
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        PrintStream ps = new PrintStream(os);
        t.printStackTrace(ps);
        return os.toString();
    }

    public DebuggableThread(String name) {
        super(getStackTrace(name));
    }

    public static void main(String[] args) throws Exception {
        System.out.println(new Thread());
        System.out.println(new DebuggableThread("MainTest"));
    }
}

2 つの名前を比較した出力のサンプルを次に示します。

Thread[Thread-1,5,main]
Thread[java.lang.Throwable: DebuggableThread-MainTest
    at DebuggableThread.getStackTrace(DebuggableThread.java:6)
    at DebuggableThread.<init>(DebuggableThread.java:14)
    at DebuggableThread.main(DebuggableThread.java:19)
,5,main]
于 2012-06-19T23:12:49.857 に答える
12

これは非常に人気のあるトピックであり、優れた回答は全体に広がっており、非常に深く扱われているため、他の人からの優れた回答をより簡潔な形式にまとめることが正当であると感じました。

  1. 通常、クラスを拡張して機能を追加または変更します。そのため、スレッドの動作上書きたくない場合は、Runnable を使用してください。

  2. 同様に、スレッド メソッドを継承する必要がない場合は、 Runnable を使用することでそのオーバーヘッドをなくすことができます。

  3. 単一継承: Thread を拡張する場合、他のクラスから拡張することはできないため、それが必要な場合は、Runnable を使用する必要があります。

  4. ドメイン ロジックを技術的な手段から分離するのは良い設計です。その意味で、タスクをランナーから分離する Runnable タスクを用意する方よいでしょう。

  5. 同じ Runnableオブジェクトを複数回実行できますが、Thread オブジェクトは 1 回しか開始できません。(おそらく、Executor が Runnables を受け入れるのに Threads を受け入れない理由です。)

  6. タスクを Runnable として開発すると、現在および将来の使用方法に柔軟性があります。Executors を介して同時に実行することも、Thread を介して実行することもできます。また、他の通常のタイプ/オブジェクトと同じように、同じスレッド内で同時に使用/呼び出しすることもできます。

  7. これにより、単体テストタスク ロジックと同時実行の側面を簡単に分離できます。

  8. この質問に興味がある場合は、 Callable と Runnable の違いにも興味があるかもしれません。

于 2014-02-13T09:07:11.560 に答える
12

実行可能な理由:

  • Runnable 実装が別のクラスを拡張するための柔軟性を残します
  • コードを実行から分離する
  • 今後、スレッド プール、イベント スレッド、またはその他の方法でランナブルを実行できるようにします。

今は必要なくても、将来必要になるかもしれません。Thread をオーバーライドしてもメリットがないため、Runnable の方が優れたソリューションです。

于 2010-05-07T04:28:57.637 に答える
9

これについては、Oracle のスレッドの定義と開始のチュートリアルで説明されています。

これらのイディオムのどれを使用する必要がありますか? Runnable オブジェクトを使用する最初のイディオムは、より一般的です。Runnable オブジェクトは Thread 以外のクラスをサブクラス化できるからです。2 番目のイディオムは単純なアプリケーションでは使いやすいですが、タスク クラスが Thread の子孫でなければならないという事実によって制限されます。このレッスンでは、タスクを実行する Thread オブジェクトから Runnable タスクを分離する最初のアプローチに焦点を当てます。このアプローチは柔軟性が高いだけでなく、後で説明する高レベルのスレッド管理 API にも適用できます。

つまり、実装Runnableは、クラスが 以外のクラスを拡張するシナリオで機能しますThread。Java は多重継承をサポートしていません。また、一部の高レベル スレッド管理 API を使用する場合は拡張Threadできません。拡張が望ましい唯一のシナリオはThread、将来更新の対象とならない小さなアプリケーションです。Runnableプロジェクトが成長するにつれてより柔軟になるため、ほとんどの場合、実装することをお勧めします。Java では多くのインターフェイスを実装できますが、拡張できるクラスは 1 つだけなので、設計変更は大きな影響を与えません。

于 2014-01-21T16:44:09.417 に答える
9

最も簡単な説明はRunnable、同じオブジェクトを複数のスレッドに割り当て、それぞれThreadが同じオブジェクトの状態と動作を共有できるようにすることです。

たとえば、2 つのスレッドがあり、配列がいっぱいになると、thread1が整数を配列に入れ、thread2が配列から整数を取得するとします。スレッド 2 が機能するためには、スレッド 1がいっぱいになっているかどうかにかかわらず、配列の状態を知る必要があることに注意してください。

実装Runnableすると、オブジェクトを共有する柔軟性が得られますが、extends Threadスレッドごとに新しいオブジェクトを作成する必要があるため、スレッド 1 によって行われた更新はスレッド 2 に失われます。

于 2015-08-14T08:07:40.853 に答える
6

Thread クラスを Runnable 実装から分離すると、スレッドと run() メソッド間の潜在的な同期の問題も回避されます。別の Runnable を使用すると、通常、実行可能なコードを参照して実行する方法がより柔軟になります。

于 2010-03-08T07:03:06.130 に答える
6

runnable を使用すると、スペースを節約して他のクラスに拡張できます。

于 2013-09-26T05:58:02.810 に答える
6

それがSOLIDのS:単独責任。

スレッドは、コード片の非同期実行の実行コンテキスト(実行コンテキスト: スタック フレーム、スレッド ID など) を具体化します。そのコードは、理想的には、同期または非同期のいずれであっても、同じ実装である必要があります。

それらを 1 つの実装にまとめると、結果のオブジェクトに 2 つの無関係な変更の原因が与えられます。

  1. アプリケーションでのスレッド処理 (つまり、実行コンテキストのクエリと変更)
  2. コード片によって実装されるアルゴリズム (実行可能な部分)

使用する言語が部分クラスまたは多重継承をサポートしている場合、それぞれの原因を独自のスーパー クラスに分離できますが、機能セットが重複しないため、2 つのオブジェクトを構成するのと同じになります。それは理論のためです。

実際には、一般的に言えば、プログラムは必要以上に複雑にする必要はありません。特定のタスクで作業するスレッドが 1 つあり、そのタスクをまったく変更しない場合、おそらくタスクを別のクラスにする意味はなく、コードは単純なままです。

Javaのコンテキストでは、機能が既に存在するため、スタンドアロンRunnableクラスから直接開始して、それらのインスタンスをThread(またはExecutor) インスタンスに渡す方がおそらく簡単です。そのパターンに慣れると、単純な実行可能なスレッドのケースよりも使用(または読み取り) が難しくありません。

于 2013-03-18T10:14:31.730 に答える
6

Runnableはインターフェースで、Threadはこのインターフェースを実装するクラスです。設計の観点からは、タスクの定義方法と実行方法を明確に分離する必要があります。前者は実装の責任でRunnalbeあり、後者はThreadクラスの仕事です。ほとんどの場合、実装Runnableは従うべき正しい方法です。

于 2012-08-18T17:47:11.317 に答える
5

上記のすべての理由から Runnable を使用するのが最も便利だと思いますが、独自のスレッド停止メソッドを作成し、作成したスレッドで直接呼び出すことができるように、Thread を拡張したい場合もあります。

于 2012-06-09T19:09:15.987 に答える
5

Java は多重継承をサポートしていないため、Thread クラスを拡張すると、他のクラスは拡張されません。

例: アプレットを作成する場合、アプレット クラスを拡張する必要があるため、スレッドを作成する唯一の方法は、Runnable インターフェイスを実装することです。

于 2012-06-09T19:28:31.597 に答える
5

はい、ThreadA call を呼び出す場合は、start メソッドを呼び出す必要はなく、run メソッドは ThreadA クラスのみを呼び出した後に呼び出します。ただし、ThreadB 呼び出しを使用する場合は、run メソッドを呼び出すための開始スレッドが必要です。さらに助けがあれば、私に返信してください。

于 2012-01-28T08:31:16.623 に答える
5

ここに私の 2 セントを追加します - 可能な限りいつでも使用してimplements Runnableください。extends Thread以下は、 sを使用すべきではない理由に関する 2 つの注意事項です。

  1. 理想的には、Thread クラスを拡張しないでください。Threadクラスを作成する必要がありますfinal。少なくともthread.getId(). s の拡張に関連するバグについては、このディスカッションを参照してくださいThread

  2. パズルを解くのが好きな人は、Thread を拡張することの別の副作用を見ることができます。以下のコードは、誰も通知していないときに到達不能なコードを出力します。

http://pastebin.com/BjKNNs2Gをご覧ください 。

public class WaitPuzzle {

    public static void main(String[] args) throws InterruptedException {
        DoNothing doNothing = new DoNothing();
        new WaitForever(doNothing).start();
        new WaitForever(doNothing).start();
        new WaitForever(doNothing).start();
        Thread.sleep(100);
        doNothing.start();
        while(true) {
            Thread.sleep(10);
        }
    }


    static class WaitForever extends  Thread {

        private DoNothing doNothing;

        public WaitForever(DoNothing doNothing) {
            this.doNothing =  doNothing;
        }

        @Override
        public void run() {
            synchronized (doNothing) {
                try {
                    doNothing.wait(); // will wait forever here as nobody notifies here
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Unreachable Code");
            }
        }
    }

    static class DoNothing extends Thread {

        @Override
        public void run() {
            System.out.println("Do Nothing ");
        }
    } 
}
于 2015-01-03T00:11:56.637 に答える
4

Runnable の実装と Thread の拡張の違いの 1 つは、Thread を拡張すると、各スレッドに固有のオブジェクトが関連付けられるのに対し、Runnable を実装すると、多くのスレッドが同じオブジェクト インスタンスを共有できることです。

Runnable を実装するクラスはスレッドではなく、単なるクラスです。Runnable を Thread で実行するには、Thread のインスタンスを作成し、Runnable インスタンスをターゲットとして渡す必要があります。

ほとんどの場合、run() メソッドのみをオーバーライドし、他の Thread メソッドをオーバーライドしない場合は、Runnable インターフェースを使用する必要があります。プログラマーがクラスの基本的な動作を変更または強化するつもりでない限り、クラスをサブクラス化するべきではないため、これは重要です。

スーパークラスを拡張する必要がある場合は、Thread クラスを使用するよりも Runnable インターフェースを実装する方が適切です。Runnable インターフェイスを実装してスレッドを作成しながら、別のクラスを拡張できるためです。しかし、Thread クラスを拡張しただけでは、他のクラスから継承することはできません。

于 2015-02-19T05:37:40.550 に答える
3

スレッドは、アクセスを意図していない動作を保持しています。

  • ジョインなどにシンクロロックが使われます。
  • 偶然アクセスできるメソッドがあります。

ただし、スレッドをサブクラス化する場合は、より多くのスレッドが実装されていることを考慮する必要があります。

public class ThreadMain {
    public int getId() {
        return 12345678;
    }

    public String getName() {
        return "Hello World";
    }

    public String getState() {
        return "testing";
    }

    public void example() {
        new Thread() {
            @Override
            public void run() {
                System.out.println("id: "+getId()+", name: "+getName()+", state: "+getState());
            }
        }.start();
    }

    public static void main(String[] args) {
        new ThreadMain().example();
    }
}

これを実行すると、期待できるかもしれません

id: 12345678, name: Hello World, state: testing

Threadただし、メソッドをnotで使用しているため、自分が思っているメソッドを呼び出していません。ThreadMain代わりに、次のようなものが表示されます

id: 11, name: Thread-0, state: RUNNABLE
于 2015-07-26T18:01:29.560 に答える
2

これは答えではないかもしれませんが、とにかく; スレッドを作成する方法がもう 1 つあります。

Thread t = new Thread() {
    public void run() {
        // Code here
    }
}
于 2012-07-06T15:12:39.930 に答える
2

まれに、一度だけ実行する場合は、DRY のためにスレッドを拡張する必要があります。複数回呼び出す場合は、同じスレッドを再起動してはならないため、Runnable を実装する必要があります。

于 2016-11-10T07:05:51.520 に答える
0

簡単な言い方は次のとおりです。インターフェイスを実装する場合は、そのすべてのメソッドを実装することを意味し、クラスを拡張する場合は、選択したメソッドを継承します...この場合、Run() という名前のメソッドは 1 つしかありません。 Runnable インターフェイスを実装する方が良い..

于 2014-06-18T07:22:39.580 に答える
-1

Thread と Runnable の主な違いは次のとおりです。 - Thread は次のようなものです: Worker (Runnable を実行します)

于 2018-12-05T03:58:43.357 に答える