Почему два потока 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.websequencediagrams.com/cgi-bin / cdraw LZ = TWFpbi0-RXhhbXBsZTE6IFRhc2sgc3RhcnRlZAphY3RpdmF0ZSAAGAgKACEILS0-TWFpbjogZG9uZQpkZQAYEgABWAABWAABgTFlMQo & амп;? s = салфетку р>
Вот диаграмма последовательности салфеток того, что происходит во втором тесте: http://www.websequencediagrams.com/cgi-bin/cdraw?lz = TWFpbi0tPkFub255bW91cyBUaHJlYWQ6IFN0YXJ0IEV4YW1wbGUxLnRhc2soKQoACSYyAAEuAAFdAAGBOwCCPjoAgyIGPk1haW46ICJIb3cgbG9uZyBkaWQgdGhhdCB0YWtlPyIKAINmEC0AKwhUYXNrcyBiZWdpbiB0byBmaW5pc2guLi4gKHNvbWUgbWF5IGhhdmUgZW5kZWQgZWFybGllcikK & амп; s = салфетку р>
Редактировать 3: Я только что понял, что вторая диаграмма последовательности указывает все стрелки на / same / нить. Они на самом деле разные темы, каждый вызов.
Другие советы
Вызов 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 (), потому что другие потоки не блокируются. Если поток завершил свою работу перед вызовом присоединения, вы просто переходите к следующему потоку.
Кроме того, что означает ваш последний комментарий?