Pourquoi deux threads Java (dans certains cas) sont-ils plus de deux fois plus rapides qu'un?
-
22-07-2019 - |
Question
Fichier: 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);
}
}
Fichier: 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;
}
}
}
Lorsque je lance ceci, il génère:
Durée d'exécution pour un thread: 1219
Durée d'exécution pour deux threads: 281
ou quelque chose de très proche.
Pourquoi y a-t-il une telle différence? Pourquoi le scinder en deux threads va-t-il plus de deux fois plus vite que de le lancer directement?
La solution
En fait, vous n'attendez pas que les discussions se terminent.
Une fois que vous avez démarré un fil de discussion, vous devez ensuite appeler .join () dessus pour attendre son achèvement. Ce qui se passe ici, c’est que tous vos threads commencent et dès que le dernier a commencé, vous le chronométrez et vous calculez l’heure de fin. Cela signifie que vos threads fonctionnent toujours en arrière-plan.
Éditer: la première raison est si longue parce que vous effectuez une série d'appels synchrones lorsque vous créez un thread et que vous le démarrez, ce qui génère une tâche asynchrone.
Éditer 2: Voici un diagramme de séquence de serviettes illustrant ce qui se passe lors de votre premier test:
http://www.websequencediagrams.com/cgi-bin / cdraw? lz = TWFpbi0-RXhhbXBsZTE6IFRhc2sgc3RhcnRlZAphY3RpdmF0ZSAAGAgKACEILS0-TWFpbjogZG9uZQpkZQkQQEQAEFABHABO & F;
Voici un diagramme de séquence de serviettes illustrant ce qui se passe dans votre deuxième test:
http://www.websequencediagrams.com/cgi-bin/cdraw?lz = TWFpbi0tPkFub255bW91cyBUaHJlYWQ6IFN0YXJ0IEV4YW1wbGUxLnRhc2soKQoACSYyAAEuAAFdAAGBOwCCPjoAgyIGPk1haW46ICJIb3cgbG9uZyBkaWQgdGhhdCB0YWtlPyIKAINmEC0AKwhUYXNrcyBiZWdpbiB0byBmaW5pc2guLi4gKHNvbWUgbWF5IGhhdmUgZW5kZWQgZWFybGllcikK & amp; s = serviette Éditer 3: Je viens de me rendre compte que le deuxième diagramme de séquence pointe toutes les flèches vers le / même / fil. Ce sont en fait différents threads, chaque appel.
Autres conseils
L'appel start () sur un thread est renvoyé immédiatement car il met simplement en file d'attente le thread. Le fil lui-même commencera à s’exécuter en arrière-plan un peu plus tard.
Voici ce que j'obtiens avec votre code en ajoutant join aux discussions:
Durée d'exécution pour un thread: 566
Durée d'exécution pour deux threads: 294
Les réponses précédentes sont donc correctes.
EDIT: J'ai ajouté des jointures de cette façon. Vous pouvez le faire mieux, mais peu importe:
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();
}
}
Vous devez rejoindre chaque fil de discussion. Cependant, vous ne perdez pas votre temps à attendre dans join () car les autres threads ne sont pas bloqués. Si le thread a terminé son exécution avant que vous appeliez à rejoindre le groupe, continuez simplement au prochain thread.
De plus, que signifie votre dernier commentaire?