2つのJavaスレッドが(場合によって)1つの2倍以上の速度になるのはなぜですか?
-
22-07-2019 - |
質問
ファイル:Example1.java
public class Example1 implements Runnable {
public void run() {
for(int i = 0; i < 100000000; i++) {
int x = 5;
x = x * 4;
x = x % 3;
x = x + 9000;
x = x * 923;
}
}
public static void task() {
for(int i = 0; i < 100000000; i++) {
int x = 5;
x = x * 4;
x = x % 3;
x = x + 9000;
x = x * 923;
}
for(int i = 0; i < 100000000; i++) {
int x = 9;
x = x * 2;
x = x % 4;
x = x + 3241;
x = x * 472;
}
}
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
Example1.task();
Example1.task();
Example1.task();
Example1.task();
Example1.task();
long stopTime = System.currentTimeMillis();
long runTime = stopTime - startTime;
System.out.println("Run time for one thread: " + runTime);
startTime = System.Example1();
(new Thread(new Example1())).start();
(new Thread(new Example2())).start();
(new Thread(new Example1())).start();
(new Thread(new Example2())).start();
(new Thread(new Example1())).start();
(new Thread(new Example2())).start();
(new Thread(new Example1())).start();
(new Thread(new Example2())).start();
(new Thread(new Example1())).start();
(new Thread(new Example2())).start();
stopTime = System.currentTimeMillis();
runTime = stopTime - startTime;
System.out.println("Run time for two threads: " + runTime);
}
}
ファイル:Example2.java
public class Example2 implements Runnable {
public void run() {
for(int i = 0; i < 100000000; i++) {
int x = 9;
x = x * 2;
x = x % 4;
x = x + 3241;
x = x * 472;
}
}
}
これを実行すると、次が出力されます:
1つのスレッドの実行時間:1219
2つのスレッドの実行時間:281
または非常に近いもの。
なぜそんな違いがあるのですか? 2つのスレッドに分割すると、直接実行するよりも2倍以上速くなるのはなぜですか?
解決
実際には、スレッドが終了するのをまったく待っていません。
スレッドを開始したら、そのスレッドで.join()を呼び出して、スレッドの完了を待機する必要があります。ここで何が起こっているのかは、すべてのスレッドが開始され、最後のスレッドが開始されるとすぐに、それを計時してから停止時間を計算することです。これは、スレッドがまだバックグラウンドで実行されていることを意味します。
編集:最初の呼び出しに非常に時間がかかるのは、スレッドを作成して開始するときに非同期タスクが生成される間に一連の同期呼び出しを行うためです。
編集2:これは、最初のテストで行われることのナプキンシーケンス図です。 http://www.websequencediagrams.com/cgi-bin/cdraw?lz = TWFpbi0tPkFub255bW91cyBUaHJlYWQ6IFN0YXJ0IEV4YW1wbGUxLnRhc2soKQoACSYyAAEuAAFdAAGBOwCCPjoAgyIGPk1haW46ICJIb3cgbG9uZyBkaWQgdGhhdCB0YWtlPyIKAINmEC0AKwhUYXNrcyBiZWdpbiB0byBmaW5pc2guLi4gKHNvbWUgbWF5IGhhdmUgZW5kZWQgZWFybGllcikK&#038; S =ナプキンの
編集3:2番目のシーケンス図がすべての矢印を/ same /スレッドに向けていることに気付きました。実際には、それぞれが異なるスレッドです。
他のヒント
スレッドをキューに登録するだけなので、スレッドのstart()呼び出しはすぐに戻ります。 スレッド自体は、しばらくしてバックグラウンドで実行を開始します。
ここに、スレッドに結合を追加するコードで得られるものを示します。
1つのスレッドの実行時間:566
2つのスレッドの実行時間:294
したがって、以前の回答は正しいです。
編集:この方法で結合を追加しました。あなたはそれをより良くすることができますが、それは問題ではありません:
Thread[] t = new Thread[10];
(t[0] = new Thread(new Example1())).start();
(t[1] = new Thread(new Example2())).start();
(t[2] = new Thread(new Example1())).start();
(t[3] = new Thread(new Example2())).start();
(t[4] = new Thread(new Example1())).start();
(t[5] = new Thread(new Example2())).start();
(t[6] = new Thread(new Example1())).start();
(t[7] = new Thread(new Example2())).start();
(t[8] = new Thread(new Example1())).start();
(t[9] = new Thread(new Example2())).start();
for (Thread t1: t) {
try {
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
各スレッドに参加する必要があります。ただし、他のスレッドがブロックされないため、join()で待機する時間を無駄にしません。スレッドが参加を呼び出す前に実行を終了した場合、次のスレッドに進みます。
また、最後のコメントはどういう意味ですか?