왜 두 개의 Java 스레드 (경우에 따라)가 하나보다 두 배 이상 빠른 이유는 무엇입니까?
-
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;
}
}
}
이것을 실행하면 출력이 있습니다.
하나의 스레드에 대한 시간 : 1219
두 스레드에 대한 시간 : 281
또는 아주 가까운 것.
왜 그런 차이가 있습니까? 두 스레드로 나누는 것이 왜 직접 실행하는 것보다 두 번 이상 빠르게 진행됩니까?
해결책
당신은 실제로 스레드가 전혀 끝날 때까지 기다리지 않습니다.
스레드를 시작하면 스레드가 완료되기를 기다리려면 .join ()을 호출해야합니다. 여기서 일어나는 일은 모든 스레드가 시작되고 마지막 스레드가 시작 되 자마자 시계를 치고 정지 시간을 계산한다는 것입니다. 이것은 당신의 스레드가 여전히 백그라운드에서 실행되고 있음을 의미합니다.
편집 : 첫 번째 시간이 오래 걸리는 이유는 일련의 동기 호출을하고 스레드를 만들고 시작하면 비동기 작업을 시작하기 때문입니다.
편집 2 : 첫 번째 테스트에서 발생하는 일에 대한 냅킨 시퀀스 다이어그램이 있습니다.http://www.webestenceationiagrams.com/cgi-bin/cdraw?lz=twfpbi0-rxhhbxzte6ifrhc2sgc3rhcnrlzaphy3rpdmf0zsaagagkaceils0-twfbjogzg9uzqpkzqwwaabgwaabgwaabgwaabgwaabgwaabgwaabgwaabgwaabgwaabgwaabg
다음은 두 번째 테스트에서 발생하는 일에 대한 냅킨 시퀀스 다이어그램입니다.http://www.websequencediagrams.com/cgi-bin/cdraw?lz=TWFpbi0tPkFub255bW91cyBUaHJlYWQ6IFN0YXJ0IEV4YW1wbGUxLnRhc2soKQoACSYyAAEuAAFdAAGBOwCCPjoAgyIGPk1haW46ICJIb3cgbG9uZyBkaWQgdGhhdCB0YWtlPyIKAINmEC0AKwhUYXNrcyBiZWdpbiB0byBmaW5pc2guLi4gKHNvbWUgbWF5IGhhdmUgZW5kZWQgZWFybGllcikK&s=napkin
편집 3 : 방금 두 번째 시퀀스 다이어그램이 모든 화살표를 / 동일한 / 스레드로 가리킨다는 것을 깨달았습니다. 그들은 실제로 다른 스레드, 각 호출입니다.
다른 팁
스레드에서 start ()가 스레드를 큐에 넣기 때문에 즉시 돌아옵니다. 스레드 자체는 얼마 후에 백그라운드에서 실행되기 시작합니다.
다음은 스레드에 조인을 추가하는 코드를 사용하여 얻는 것입니다.
하나의 스레드에 대한 시간 : 566
두 개의 스레드에 대한 시간 : 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 ()에서 대기하는 시간을 낭비하지 않습니다. 스레드가 완료되면 가입하기 전에 실행을 완료하면 다음 스레드로 계속 진행됩니다.
또한 마지막 의견은 무엇을 의미합니까?