私がJavaでスレッドを使っていたときから、スレッドを書くための2つの方法を見つけました。
implements 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つのコードブロックに大きな違いはありますか?
はい:実装Runnable
はそれを実行するのに好ましい方法です、IMO。あなたは本当にスレッドの振る舞いを専門にしていません。あなたはただそれに走らせる何かを与えているのです。つまり、 composition は 哲学的に "より純粋な"方法です。
実用的な の用語では、それはあなたがRunnable
を実装し、他のクラスからも拡張できることを意味します。
tl; dr:Runnableが実装されています。ただし、注意が重要です
一般的に、Runnable
よりもThread
のようなものを使用することをお勧めします。なぜならそれはあなたの作業をあなたの並行性の選択と緩やかに結びつけるだけにすることを可能にするからです。例えば、あなたがRunnable
を使用し、後でこれが実際にそれ自身のThread
を必要としないと決めるなら、あなたはただthreadA.run()を呼び出すことができます。
警告: このあたりでは、生のスレッドの使用をお勧めしません。私は Callables と FutureTasks を使うことを好みます(Javadocより: "キャンセル可能な非同期計算")。タイムアウトの統合、適切なキャンセル、最新の並行処理サポートのスレッドプーリングは、生のThreadを重ねるよりもずっと便利です。
フォローアップ: あなたがRunnablesを使うことを可能にする FutureTask
コンストラクター がありますが(それがあなたが最も快適なものである場合)、それでも現代の並行処理ツールの恩恵を受けます。 Javadocを引用するには:
特に結果が必要ない場合は、次の形式の構成を使用することを検討してください。
Future<?> f = new FutureTask<Object>(runnable, null)
したがって、それらのrunnable
をあなたのthreadA
に置き換えると、次のようになります。
new FutureTask<Object>(threadA, null)
Runnablesにもっと近づくことができるもう1つのオプションは ThreadPoolExecutor です。 execute メソッドを使用すると、Runnableを渡して「将来的に特定のタスクを実行する」ことができます。
スレッドプールを使用したい場合は、上記のコードフラグメントは次のようになります( Executors.newCachedThreadPool() factoryメソッドを使用)。
ExecutorService es = Executors.newCachedThreadPool();
es.execute(new ThreadA());
この話の教訓:
何らかの動作をオーバーライドする場合にのみ継承します。
それどころか、それは次のように読まれるべきです:
継承を減らし、インタフェースを継承します。
そう多くのよい答え、私はこれについてもっと加えたいと思います。これはExtending v/s Implementing Thread
を理解するのに役立ちます。
Extendsは2つのクラスファイルを非常に密接に結び付けているため、コードを扱うのがかなり難しい場合があります。
どちらのアプローチも同じ働きをしますが、いくつかの違いがあります。
最も一般的な違いは です。
しかし、 大きな違い Runnableの実装とThreadの拡張の違いは、
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つのインスタンスのみが作成され、それは異なるスレッドによって共有されています。したがって、counterの値は、スレッドアクセスごとに増加します。
一方、Threadクラスのアプローチでは、スレッドアクセスごとに個別のインスタンスを作成する必要があります。したがって、クラスインスタンスごとに異なるメモリが割り当てられ、それぞれが別々のカウンタを持ち、値は同じままです。つまり、オブジェクト参照が同じではないため、増分は発生しません。
Runnableを使用する場合
スレッドのグループから同じリソースにアクセスしたい場合は、Runnableインターフェースを使用してください。ここではThreadクラスを使用しないでください。複数のオブジェクトを作成するとより多くのメモリが消費され、パフォーマンスの大幅なオーバーヘッドになるためです。
Runnableを実装するクラスはスレッドではなく、単なるクラスです。 RunnableがThreadになるには、Threadのインスタンスを作成し、それ自体をターゲットとして渡す必要があります。
ほとんどの場合、run()
メソッドをオーバーライドするだけで他のThreadメソッドをオーバーライドすることを計画していない場合は、Runnableインターフェースを使用する必要があります。プログラマがクラスの基本的な振る舞いを修正または強化するつもりでない限り、クラスをサブクラス化しないでください。
スーパークラスを拡張する必要がある場合は、Threadクラスを使用するよりもRunnableインターフェイスを実装する方が適切です。スレッドを作成するためにRunnableインターフェースを実装しながら別のクラスを拡張できるからです。
これが役立つことを願っています!
私が驚いたのは、まだ言及されていないことですが、Runnable
を実装するとクラスがより柔軟になるということです。
あなたがスレッドを拡張するならば、あなたがしている行動は常にスレッドの中にあることになるでしょう。しかし、あなたがRunnable
を実装するのであれば、そうする必要はありません。スレッドで実行するか、ある種のエグゼキュータサービスに渡すか、シングルスレッドアプリケーション内のタスクとして渡すことができます(後で実行するために同じスレッド内で実行することもできます)。単にRunnable
を使う方がThread
に縛られるよりも、オプションはもっとオープンです。
他のクラスを実装または拡張したい場合はRunnable
インターフェースが最も適しています。それ以外の場合は、他のクラスを拡張または実装したくない場合はThread
クラスが好ましいです。
最も一般的な違いは です。
クラスをextends Thread
にすると、それ以降は必要なクラスを拡張できなくなります。 (ご存知のとおり、Javaでは複数のクラスを継承することはできません)。
あなたがimplements Runnable
するとき、あなたはあなたのクラスが将来あるいは現在他のクラスを拡張するためのスペースを節約することができます。
Javaは多重継承をサポートしていません。つまり、Javaでは1つのクラスしか拡張できないため、Threadクラスを拡張するとチャンスがなくなり、Javaの別のクラスを拡張または継承することはできません。
オブジェクト指向プログラミングでは、クラスを拡張することは一般に、新しい機能を追加し、動作を変更または改善することを意味します。 Threadを変更しない場合は、代わりにRunnableインターフェースを使用してください。
Runnableインターフェースは、単純なThread、Executors、またはその他の方法で実行できるタスクを表します。タスクをスレッドよりも実行可能として論理的に分離することは、良い設計上の決定です。
タスクをRunnableとして分離するということは、タスクを再利用できるということであり、また異なる方法からタスクを実行する自由もあります。完了したスレッドは再起動できません。タスクのために再びRunnable対Thread、Runnableが勝者です。
Javaデザイナーはこれを認識しています、そしてそれがExecutorsがタスクとしてRunnableを受け入れ、それらがそれらのタスクを実行するワーカースレッドを持っているのはそのためです。
すべてのThreadメソッドを継承することは、Runnableを使用して簡単に実行できるタスクを表すための追加のオーバーヘッドです。
javarevisited.blogspot.com からのご厚意
これらは、JavaにおけるThreadとRunnableとの間の顕著な違いのいくつかでした。もしあなたがThread vs Runnableに関して他の違いを知っているならコメントでそれを共有してください。私はこのシナリオではRunnable over Threadを個人的に使用していますが、要件に応じてRunnableまたはCallableインターフェースを使用することをお勧めします。
ただし、大きな違いはあります。
あなたがextends Thread
クラスを作るとき、あなたのそれぞれのスレッドはユニークなオブジェクトを作成しそれと関連します。あなたがimplements Runnable
するとき、それは同じオブジェクトを複数のスレッドに共有します。
Runnableを実装する必要がありますが、Java 5以上で実行している場合は、new Thread
で開始するのではなく、代わりに ExecutorService を使用してください。詳細は以下を参照してください。 Javaで単純なスレッドを実装する方法 。
私は専門家ではありませんが、Threadを拡張する代わりにRunnableを実装する1つの理由を考えることができます。Javaは単一継承しかサポートしないので、1つのクラスしか拡張できません。
編集:これはもともと「インターフェースを実装することはより少ないリソースを必要とする」と言っていました。しかし、どちらにしても新しいThreadインスタンスを作成する必要があるので、これは間違っていました。
私は第三の方法があると言うでしょう:
public class Something {
public void justAnotherMethod() { ... }
}
new Thread(new Runnable() {
public void run() {
instanceOfSomething.justAnotherMethod();
}
}).start();
多分これは私の最近のJavascriptとActionscript 3の多用によって少し影響されるかもしれません、しかしこのようにあなたのクラスはRunnable
のようなかなりあいまいなインターフェースを実装する必要はありません。
Java 8のリリースでは、3番目の選択肢があります。
Runnable
は 関数型インタフェース です。これは、そのインスタンスをラムダ式またはメソッド参照で作成できることを意味します。
あなたの例は次のように置き換えることができます。
new Thread(() -> { /* Code here */ }).start()
あるいはExecutorService
とメソッド参照を使いたい場合は:
executor.execute(runner::run)
これらはあなたの例よりもはるかに短いだけでなく、他の答えでRunnable
よりThread
を使うことで述べられている利点の多くを持っています。あなたが必要とするのがあなたの例でするようにRunnable
だけであるならば、この方法は余分なクラスを作成することも避けます。
インターフェースをインスタンス化することはあなたのコードとスレッドの実装との間の明確な分離を与えるので、この場合Runnableを実装することを私は好むでしょう。
ここに誰もがRunnableを実装することが進むべき道だと思うようで、私はそれらに賛成できませんが、私の意見ではThreadを拡張する場合もあります。
Runnableを実装すると、Runnableを実装するクラスはスレッド名を制御できなくなります。このように、スレッド名を設定できるのは呼び出しコードです。
new Thread(myRunnable,"WhateverNameiFeelLike");
しかし、Threadを拡張すると、クラス自体の中でこれを管理できるようになります(この例では、スレッドを「ThreadB」と命名します)。この場合あなたは:
A)それをデバッグ目的のためにより有用な名前にするかもしれません
B)その名前がそのクラスのすべてのインスタンスに使用されることを強制している(あなたがそれがスレッドであるという事実を無視し、それがRunnableであるかのようにそれを用いて行う限り。その可能性を無視して私は感じる)。
たとえば、その作成のスタックトレースを取得し、それをスレッド名として使用することもできます。これは奇妙に思えるかもしれませんが、あなたのコードがどのように構造化されているかによりますが、デバッグ目的のために非常に役に立ちます。
これは小さなことのように思えるかもしれませんが、非常に複雑なアプリケーションで多数のスレッドを使用していて、突然すべてが「停止」した場合(デッドロックのため、またはネットワークプロトコルの欠陥のせいで)それから、すべてのスレッドが 'Thread-1'、 'Thread-2'、 'Thread-3'と呼ばれるJavaからスタックダンプを取得することは、必ずしも非常に便利というわけではありません。構造化されていて、どれがどれがどれがそれらのスタックトレースだけで有用であるかを便利に見分けることができるかどうか。
もちろん、その名前を作成呼び出しのスタックトレースに設定し、それを標準のJava Threadクラスの代わりにRunnableの実装で使用するというスレッドクラスの拡張を作成することで、一般的な方法で上記を実行することもできます。 (下記参照)しかし、スタックトレースに加えて、デバッグのためにスレッド名に役立つと思われる、よりコンテキスト固有の情報(それが処理できる多くのキューまたはソケットの1つへの参照)があるかもしれません。そのような場合のためにThreadを特別に拡張して、名前に使用するために特定の情報(問題のキューやソケットなど)をコンパイラーに渡させることができるようにします。
これは、呼び出しスタックトレースを名前とする汎用スレッドの例です。
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]
これは非常に人気のあるトピックであり、良い答えは至る所に広がり、深く掘り下げられているので、他の人からの良い答えをより簡潔な形式にまとめることは正当であると感じたので、初心者は簡単な概要を前もって持っています:
通常、クラスを拡張して機能を追加または変更します。したがって、tooverwriteanyThread behaviorを望まない場合は、Runnableを使用します。
同じ観点から、toinheritthreadメソッドが必要ない場合は、Runnableを使用してオーバーヘッドなしで実行できます。
単一継承:スレッドを拡張する場合、他のクラスからは拡張できないため、それが必要な場合は、Runnableを使用する必要があります。
ドメインロジックを技術的手段から分離するのは良い設計です。その意味では、Runnableタスク隔離yourtask fromyourrunnerを持つ方が良いです。
実行同じRunnableオブジェクトを複数回、Threadオブジェクトは一度しか起動できません。 (おそらく、エグゼキュータがスレッドではなくRunnableを受け入れる理由です。)
タスクをRunnableとして開発する場合、現在および将来の使用方法のすべての柔軟性があります。エグゼキューター経由で同時に実行することも、スレッド経由で実行することもできます。また、他の通常のタイプ/オブジェクトと同じように、同じスレッド内で非並行に使用/呼び出しすることもできます。
これにより、個別タスクロジックと同時実行のアスペクトあなたの単体テストも簡単になります。
この質問に興味がある場合は、 CallableとRunnableの違い にも興味があるかもしれません。
実行可能な理由
たとえあなたが今これを必要としなくても、将来あなたはそうするかもしれない。 Threadをオーバーライドすることには利点がないため、Runnableはより優れたソリューションです。
これについては、Oracleの スレッドの定義と開始 tutorialで説明しています。
あなたはこれらの慣用句のどれを使うべきですか? RunnableオブジェクトはThread以外のクラスをサブクラス化できるため、Runnableオブジェクトを使用する最初のイディオムはより一般的です。 2番目のイディオムは単純なアプリケーションでは使いやすいですが、タスククラスはThreadの子孫でなければならないという事実によって制限されます。このレッスンでは、Runnableタスクをタスクを実行するThreadオブジェクトから分離する最初のアプローチに焦点を当てます。このアプローチはより柔軟性があるだけでなく、後で取り上げる高水準スレッド管理APIにも適用できます。
つまり、Runnable
を実装すると、クラスがThread
以外のクラスを拡張するシナリオで機能します。 Javaは多重継承をサポートしません。また、いくつかの高レベルのスレッド管理APIを使用している場合は、Thread
を拡張することはできません。 Thread
を拡張することが望ましい唯一のシナリオは、将来の更新の対象にならない小さなアプリケーションです。 Runnable
は、プロジェクトが大きくなるにつれて柔軟になるため、ほとんどの場合は実装するほうが優れています。 Javaで多くのインターフェースを実装できるので、設計変更は大きな影響を与えませんが、1つのクラスを拡張するだけです。
私が間違っていなければ、それは多かれ少なかれ似ています
extendsは " Is A "の関係を確立し、インタフェースは ""の機能を提供します。
Runnableを実装を優先します。
"Threadを拡張する"を優先します。
一般に、スレッドの動作をオーバーライドする必要はありません。そのため、 Runnableを実装しています はほとんどの場合推奨されます。
別の言い方をすれば、高度なExecutorService
またはThreadPoolExecutorService
APIを使用すると、柔軟性と制御性が向上します。
このSEを見てみましょう質問:
最も簡単な説明は、同じオブジェクトを複数のスレッドに割り当てることができるRunnable
を実装することです。各Thread
は同じオブジェクトの状態と動作を共有します。
たとえば、2つのスレッドがあるとします。 thread1 は配列に整数を入れ、 thread2 は配列がいっぱいになったときに配列から整数を取り出します。 thread2 が機能するためには、 thread1 がそれを埋めているかどうかにかかわらず、配列の状態を知る必要があることに注意してください。
Runnable
を実装すると、オブジェクトを共有するためのこの柔軟性を持つことができます。一方、extends Thread
を使用すると、各スレッドに対して新しいオブジェクトを作成できます。そのため、thread1による更新はthread2に失われます。
ThreadクラスをRunnable実装から分離することで、スレッドとrun()メソッド間の潜在的な同期の問題も回避されます。独立したRunnableは一般に、Runnableコードが参照され実行される方法においてより大きな柔軟性を与えます。
threadはrunning contextを具体化します(実行コンテキストのように:スタックフレーム、スレッドIDなど。 )非同期実行のコードの一部。 コードの一部は、理想的にはsynchronousまたはasynchronous。
これらを1つの実装にバンドルすると、結果のオブジェクトに2つのunrelated変更の原因が与えられます。
使用する言語が部分クラスまたは多重継承をサポートしている場合、それぞれの原因を独自のスーパークラスに分離できますが、機能セットが重複しないため、2つのオブジェクトを構成するのと同じように要約されます。それが理論です。
実際には、一般的に言えば、プログラムは必要以上の複雑さを伴う必要はありません。特定のタスクで1つのスレッドが動作している場合、そのタスクを変更することなく、タスクを別々のクラスにすることはおそらく意味がなく、コードは単純なままです。
Javaのコンテキストでは、ファシリティはすでにあるので、おそらく直接開始する方が簡単ですスタンドアロンRunnable
クラスを使用し、そのインスタンスをThread
(またはExecutor
)インスタンスに渡します。そのパターンにusedを使用すると、単純な実行可能なスレッドの場合よりも使用(または読み取り)することは難しくありません。
基本クラスを拡張するのではなくインターフェースを実装したい理由の1つは、すでに他のクラスを拡張していることです。 1つのクラスしか拡張できませんが、インターフェイスはいくつでも実装できます。
あなたがThreadを拡張するならば、あなたはあなたのロジックが 'this'以外の他のスレッドによって実行されるのを基本的に妨げています。 some threadにあなたのロジックを実行させたいだけなら、Runnableを実装するほうがいいでしょう。
クラスをThread
として振る舞わせたかったという基本的な理由を再訪問できますか?まったく理由はありません。タスクを実行するには、ほとんどの場合非同期モードで実行したいと考えています。つまり、タスクの実行はメインスレッドとメインスレッドから分岐しなければならないこと分岐パス(タスク)用.
これが全体の目的であるなら、どこに私は特別なスレッドの必要性を見ますか。これはシステムのスレッドプールからRAWスレッドを選び、それに私たちのタスク(私たちのクラスのインスタンスかもしれません)を割り当てることで達成できます。
それでは、OOPの概念に従って、必要な型のクラスを書いてみましょう。物事を実行する方法はたくさんありますが、正しい方法で実行することが重要です。
タスクが必要なので、スレッド上で実行できるタスク定義を書きます。だからRunnableを使ってください。
implements
は振る舞いを付与するために特別に使用され、extends
は機能/プロパティを付与するために使用されることを常に覚えておいてください。
私たちはスレッドのプロパティを望まず、代わりに私たちのクラスが実行可能なタスクとして振る舞うことを望みます。
あなたがランナブルを使うならば、あなたはあなたの他のクラスのいずれかに拡張するためにスペースを節約することができます。
Runnableの実装とThreadの拡張の違いの1つは、Threadを拡張することで、各スレッドに一意のオブジェクトが関連付けられるのに対し、Runnableを実装すると、多くのスレッドが同じオブジェクトインスタンスを共有できることです。
Runnableを実装するクラスはスレッドではなく、単なるクラスです。 RunnableをThreadによって実行するには、Threadのインスタンスを作成し、そのRunnableインスタンスをターゲットとして渡す必要があります。
ほとんどの場合、run()メソッドをオーバーライドするだけで他のThreadメソッドをオーバーライドしない場合は、Runnableインターフェースを使用する必要があります。プログラマがクラスの基本的な振る舞いを修正または強化するつもりでない限り、クラスをサブクラス化しないでください。
スーパークラスを拡張する必要がある場合は、Threadクラスを使用するよりもRunnableインターフェイスを実装する方が適切です。スレッドを作成するためにRunnableインターフェースを実装しながら別のクラスを拡張できるからです。しかし、単にThreadクラスを拡張するだけでは、他のクラスから継承することはできません。
私が述べたすべての理由でRunnableを使用するのが最も有用であると思います、しかし時々私は私自身のスレッド停止メソッドを作成し、私が作成したスレッドでそれを直接呼び出すことができるようにThreadを拡張したいです。
ほとんどのワーカースレッドにとって最善の方法は、スレッド化をワーカークラスに完全にカプセル化して、外部からの干渉がなく、不要で無効なスレッド/クラス状態を引き起こすことがないようにすることです。
例を投稿したところですので、これもあなたと共有します。
/**
* This worker can only run once
* @author JayC667
*/
public class ProperThreading {
private final Thread mThread = new Thread(() -> runWorkingLoop()); // if you want worker to be able to run multiple times, move initialisation into startThread()
private volatile boolean mThreadStarted = false;
private volatile boolean mStopRequested = false;
private final long mLoopSleepTime;
public ProperThreading(final long pLoopSleepTime /* pass more arguments here, store in members */ ) {
mLoopSleepTime = pLoopSleepTime;
}
public synchronized void startThread() {
if (mThreadStarted) throw new IllegalStateException("Worker Thread may only be started once and is already running!");
mThreadStarted = true;
mThread.start();
}
private void runWorkingLoop() {
while (!mStopRequested /* && other checks */ ) {
try {
// do the magic work here
Thread.sleep(mLoopSleepTime);
} catch (final InterruptedException e) {
break;
} catch (final Exception e) {
// do at least some basic handling here, you should NEVER ignore exception unless you know exactly what you're doing, and then it should be commented!
}
}
}
public synchronized void stopThread() {
if (!mThreadStarted) throw new IllegalStateException("Worker Thread is not even running yet!");
mStopRequested = true;
mThread.interrupt();
}
}
Threadとrunnableの違い。Threadクラスを使用してThreadを作成している場合は、作成したオブジェクトの数と等しい数のThreadになります。 runnableインターフェースを実装することによってスレッドを作成している場合は、複数のスレッドを作成するために単一のオブジェクトを使用できます。
だから私たちのデータがセンシティブではないかどうか要件に応じて。そのため、Runnableインターフェイスを使用できる複数のスレッド間で共有できます。
ここに2セントを追加します - 可能な限り常にimplements Runnable
を使用してください。以下は、extends Thread
s を使用してはいけない理由に関する2つの注意点です。
理想的には、Threadクラスを拡張しないでください。 Thread
クラスはfinal
にするべきです。少なくともそのメソッドはthread.getId()
のように。 Thread
sの拡張に関連するバグについては this の議論を参照してください。
パズルを解くのが好きな人は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 ");
}
}
}
Javaは多重継承をサポートしていないので、Threadクラスを拡張しても他のクラスは拡張されません。
例:あなたがアプレットを作成する場合、それはAppletクラスを拡張しなければならないので、ここでスレッドを作成する唯一の方法はRunnableインターフェースを実装することである
はい、ThreadA呼び出しを呼び出す場合は、startメソッドを呼び出す必要はなく、runメソッドはThreadAクラスのみを呼び出した後に呼び出します。しかし、ThreadB呼び出しを使用する場合は、呼び出しrunメソッドに開始スレッドが必要です。あなたがこれ以上の助けがあるならば、私に答えてください。
Runnable
はインターフェースですが、Thread
はこのインターフェースを実装するクラスです。設計の観点からは、タスクの定義方法と実行方法の間には明確な区別が必要です。前者はRunnalbe
実装の責任であり、後者はThread
クラスの仕事です。ほとんどの場合、Runnable
を実装するのが正しい方法です。
スレッドはアクセスされることを意図しない動作を保持します。
ただし、サブクラスThreadの場合は、より多くのThreadが実装されることを考慮する必要があります。
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
ではなくThreadMain
でメソッドを使用しているため、次のようなメソッドが表示されるため、自分が考えているメソッドを呼び出していません。
id: 11, name: Thread-0, state: RUNNABLE
まれに一度だけ実行しますが、DRYのためThreadを拡張する必要があります。複数回呼び出す場合は、同じスレッドを再起動しないようにRunnableを実装する必要があります。
スレッドクラスを拡張することによって、Javaは単一の継承しか許可しないため、派生クラスは他の基本クラスを拡張できません。それどころか、ランナブルインタフェースを実装することによって、クラスはまだ他の基本クラスを拡張します。
Runnableの実装とThreadの拡張の最も大きな違いは以下の通りです。
Threadを拡張することで、派生クラス自体がスレッドオブジェクトになりますが、Runnableインターフェイスを実装すると、同じオブジェクトを複数のThreadと共有します。
これは答えではないかもしれませんが、とにかく。スレッドを作成するもう1つの方法があります。
Thread t = new Thread() {
public void run() {
// Code here
}
}
1.スレッドインターフェースを拡張することは、クラスをスレッドとしてのみ振る舞わせるようなものです。あなたの新しいクラスは拡張スレッドのようになるでしょう。
jshell> public class Test extends Thread{
...> public Test(String name){
...> super(name);
...> }
...> public void run(){
...> System.out.println(Thread.currentThread().getName());
...> }
...> }
| created class Test
jshell> Test t1=new Test("MyThread");
t1 ==> Thread[MyThread,5,main]
Testオブジェクトではなくスレッドを作成します。だから、それはシングルスレッドのように振る舞うつもりです。 Testクラスのインスタンスをスレッド間で共有することはできません。
2.実行可能インターフェースを実装する。
jshell> public class Test1 implements Runnable{
...> public void run(){
...> System.out.println(Thread.currentThread().getName());
...> }
...> public String getName(){
...> return "testing";}
...> }
| created class Test1
jshell> Test1 t1=new Test1();
t1 ==> Test1@396a51ab --> this creates Test1 object.
このオブジェクトは、スレッド間で共有できます。
jshell> Thread t1=new Thread(t1,"Hai");
t ==> Thread[Hai,5,main]
jshell> Thread t=new Thread(t1,"Hai");
t ==> Thread[Hai,5,main]
この話題についてはすでにたくさん議論されていると思います。これは基本的には役に立つかもしれませんが。
簡単な言い方は、インターフェイスを実装する場合、そのすべてのメソッドを実装することを意味し、クラスを拡張する場合は、選択したメソッドを継承します...この場合、Run() so Runnableインターフェースを実装した方が良い..
スレッドクラスは、拡張クラスによってoverriden
になることができるいくつかのメソッドを定義します。しかし、スレッドを作成するためにはrun()
メソッドをオーバーライドしなければなりません。同じことがRunnable
にも当てはまります。
ただし、Runnable
はスレッドを作成するための推奨される方法です。主な理由は以下のとおりです。
Runnableはインターフェースなので、他のクラスを拡張することができます。しかし、Threadを拡張すれば、そのオプションはなくなります。
たくさんのThread
の機能を変更したり拡張したりしていない場合は、Thread
クラスを拡張することはお勧めできません。
ThreadとRunnableの主な違いは以下のとおりです。
実際のタスクはスレッドから切り離されていると思います。 Runnableの場合、タスクをThread、Executorフレームワークなどに渡すことができます。一方、Threadタスクの拡張はスレッドオブジェクト自体と結合されています。 Threadを拡張した場合、タスク分離はできません。タスクをICチップのようなものにThreadオブジェクトに焼き付けるようなものです(より具体的には、タスクへのハンドルを取得できません)。