これら2つのRunnablesがあるとします。
class R1 implements Runnable {
public void run() { … }
…
}
class R2 implements Runnable {
public void run() { … }
…
}
それでは、これはどう違いますか?
public static void main() {
R1 r1 = new R1();
R2 r2 = new R2();
r1.run();
r2.run();
}
この:
public static void main() {
R1 r1 = new R1();
R2 r2 = new R2();
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
t2.start();
}
最初の例:複数のスレッドがありません。どちらも単一の(既存の)スレッドで実行されます。スレッドを作成しません。
R1 r1 = new R1();
R2 r2 = new R2();
r1
とr2
は、Runnable
インターフェースを実装し、したがってrun()
メソッドを実装するクラスの2つの異なるオブジェクトです。 r1.run()
を呼び出すと、現在のスレッドでそれを実行していることになります。
2番目の例:2つの別々のスレッド。
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1
とt2
は、クラスのオブジェクト Thread
です。 t1.start()
を呼び出すと、新しいスレッドを開始し、その新しいスレッド内でそれを実行するためにr1
のrun()
メソッドを内部的に呼び出します。
run()
を直接呼び出すだけでは、他のメソッド呼び出しと同じように、呼び出しスレッドで実行されます。ランナブルのrun
メソッドが並列に実行されるように、実際に新しいスレッドを作成するにはThread.start()
が必要です。
違いは、Thread.start()
はrun()
メソッドを呼び出すスレッドを開始するのに対し、Runnable.run()
は現在のスレッドのrun()
メソッドを呼び出すだけです。
differenceは、プログラムがstart()
メソッドを呼び出すと、newスレッドが作成され、run()
内のコードが実行されることを意味します。newthread run()
メソッドを直接呼び出すと、no新しいthreadは作成されず、run()
内のコードが実行されます。現在のスレッドを直接.
Javaスレッドでのstart()
とrun()
の間の別の違いは、がstart()
を2回呼び出すことはできないということです。一度開始されると、2番目のstart()
メソッドはJavaではIllegalStateException
をスローしますが、run()
メソッドはordinaryメソッドであるため、複数回呼び出すことができます。
実際にはThread.start()
は新しいスレッドを作成し、独自の実行シナリオを持っています。
Thread.start()
はrun()
メソッドを非同期的に呼び出します。これは新しいThreadの状態をRunnableに変更します。
しかしThread.run()
は新しいスレッドを作成しません。代わりに、現在実行中のスレッドでrunメソッドを同期的に実行します。
あなたがThread.run()
を使っているのなら、あなたはマルチスレッドの機能をまったく使っていません。
他のメソッド呼び出しと同様に、invoke run()
は呼び出し側スレッドで実行されています。一方Thread.start()
は新しいスレッドを作成します。 run()
を呼び出すことはプログラム上のバグです。
Mainメソッドでrun()
を実行すると、mainメソッドのスレッドは実行に必要なスレッドの代わりにrun
メソッドを呼び出します。
start()
メソッドは新しいスレッドを作成し、そのためにrun()
メソッドを実行する必要があります。
Thread.start()
コードはスレッドをスケジューラに登録し、スケジューラはrun()
メソッドを呼び出します。また、Thread
はclass、Runnable
はインターフェースです。
これらの答えのほとんどは全体像を見逃しています。それは、Java言語に関する限り、t.start()
とr.run()
の間に他の2つの方法の間に違いがないということです。
どちらも単なる方法です。両方ともそれらを呼び出したスレッド内でを実行します。彼らは両方とも彼らがするためにコード化されたことは何でもし、そしてそれから彼らは両方とも、同じスレッドの中で、彼らの呼び出し側に戻る。
最大の違いは、t.start()
のコードの大部分はnative codeですが、ほとんどの場合、r.run()
のコードは純粋なJavaになります。しかし、それほど違いはありません。コードはコードです。ネイティブコードは見つけるのが難しく、見つけると理解するのが難しくなりますが、それでもコンピュータに何をすべきかを伝えるのはコードだけです。
それで、t.start()
は何をするのでしょうか?
新しいネイティブスレッドを作成し、そのスレッドがt.run()
を呼び出すように調整してから、新しいスレッドを実行するようにOSに指示します。それから戻ります。
そしてr.run()
は何をするのですか?
面白いことに、この質問をする人は書いたです。 r.run()
はあなた(つまり、それを書いた開発者が)それをするように設計したことなら何でもします。
t.start()
は、新しいスレッドが欲しいときにあなたのコードが呼び出すためにライブラリが提供するメソッドです。
r.run()
はあなたがライブラリを呼び出してin新しいスレッドを提供するメソッドです。
メンバーが作ったことは大丈夫ですので、何かを追加したいだけです。つまり、Javaは多重継承をサポートしていません。しかし、別のクラスAからクラスBを派生させたいが、1つのクラスからしか派生できない場合はどうなりますか。今の問題は、AとThreadの両方のクラスからどのように「派生」するかです。したがって、Runnable Interfaceを使うことができます。
public class ThreadTest{
public void method(){
Thread myThread = new Thread(new B());
myThread.start;
}
}
public class B extends A implements Runnable{...
run()
メソッドを直接呼び出す場合、run()
メソッドは呼び出し側スレッドの一部として実行されるため、マルチスレッド機能を使用していません。
Threadでstart()
メソッドを呼び出すと、Java仮想マシンはrun()メソッドを呼び出し、現在のスレッド(この例ではmain()
)とその他のスレッド(この例ではRunnable r1
)のスレッドが同時に実行されます。
start()
メソッドのソースコードを Thread class でご覧ください。
/**
* Causes this thread to begin execution; the Java Virtual Machine
* calls the <code>run</code> method of this thread.
* <p>
* The result is that two threads are running concurrently: the
* current thread (which returns from the call to the
* <code>start</code> method) and the other thread (which executes its
* <code>run</code> method).
* <p>
* It is never legal to start a thread more than once.
* In particular, a thread may not be restarted once it has completed
* execution.
*
* @exception IllegalThreadStateException if the thread was already
* started.
* @see #run()
* @see #stop()
*/
public synchronized void start() {
/**
* This method is not invoked for the main method thread or "system"
* group threads created/set up by the VM. Any new functionality added
* to this method in the future may have to also be added to the VM.
*
* A zero status value corresponds to state "NEW".
*/
if (threadStatus != 0)
throw new IllegalThreadStateException();
group.add(this);
start0();
if (stopBeforeStart) {
stop0(throwableFromStop);
}
}
private native void start0();
上記のコードでは、run()
メソッドへの呼び出しは見られません。
private native void start0()
はrun()
メソッドを呼び出す責任があります。 JVMはこのネイティブメソッドを実行します。
最初のケースではr1
とr2
オブジェクトのrun()
メソッドを呼び出すだけです。
2番目のケースでは、実際には2つの新しいスレッドを作成しています。
start()
はいつかrun()
を呼び出すでしょう!