2 回答

TA貢獻(xiàn)1963條經(jīng)驗(yàn) 獲得超6個(gè)贊
抱歉vesii如果我不完全理解甚至誤解你的問題,但你的英語不是很好,即使在你發(fā)表評(píng)論后我也有問題,看看使用多線程的問題是什么。
無論如何,我建議你讓你的ConfigStruct類實(shí)現(xiàn)Runnable接口,這很容易,因?yàn)樗呀?jīng)有一個(gè)run()方法。您只需要擺脫拋出已檢查的異常,因此我進(jìn)一步建議創(chuàng)建ConfigurationException一個(gè)RuntimeException您不必在方法簽名中聲明的異常。
不幸的是,您沒有提供完整的MCVE,只有代碼片段。所以我必須彌補(bǔ)其余部分才能編譯和運(yùn)行您的代碼。我只是添加了一些簡(jiǎn)單的助手/虛擬類。我的解決方案如下所示:
package de.scrum_master.app;
public enum GalishFlags {
RUN
}
package de.scrum_master.app;
public class ConfigurationException extends RuntimeException {
private static final long serialVersionUID = 1L;
public ConfigurationException(String message, Throwable cause) {
super(message, cause);
}
}
package de.scrum_master.app;
import java.io.IOException;
public class ExternalCommandExecutor {
public static String execute(final String cmd, final String error, final boolean runInBackground, final boolean retry) throws IOException {
System.out.println("Executing external command: " + cmd);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
return cmd;
}
}
如您所見,命令執(zhí)行器在將內(nèi)容打印到控制臺(tái)后等待 100 毫秒。如果您希望程序運(yùn)行得更慢或什至隨機(jī)化以模擬需要不同時(shí)間完成的命令,您也可以將其更改為 1000 毫秒。
現(xiàn)在我們需要一個(gè)小的驅(qū)動(dòng)程序應(yīng)用程序,我們可以在其中生成配置并運(yùn)行它們。解決你從不同時(shí)運(yùn)行超過 5 個(gè)線程的問題的關(guān)鍵是通過創(chuàng)建一個(gè)固定的線程池Executors.newFixedThreadPool(5)。其余的應(yīng)該很容易理解。
package de.scrum_master.app;
import java.io.IOException;
public class ConfigStruct implements Runnable {
private String name;
public ConfigStruct(String name) {
this.name = name;
}
@Override
public void run() {
StringBuffer runCmd = generateGalishFullCommand(GalishFlags.RUN);
try {
ExternalCommandExecutor.execute(runCmd.toString(), "Failed to run " + name, true, true);
} catch (IOException e) {
throw new ConfigurationException(e.getMessage(), e);
}
}
private StringBuffer generateGalishFullCommand(GalishFlags run) {
return new StringBuffer("Galish full command for ConfigStruct '" + name + "'");
}
}
package de.scrum_master.app;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class Application {
public void runConfigurations(List<ConfigStruct> configurations) {
for (ConfigStruct configuration : configurations) {
try {
configuration.run();
} catch (ConfigurationException e) {
continue;
}
}
}
public void runConfigurationsThreaded(List<ConfigStruct> configurations) {
ExecutorService executorService = Executors.newFixedThreadPool(5);
for (ConfigStruct configuration : configurations)
executorService.execute(configuration);
executorService.shutdown();
try {
executorService.awaitTermination(30, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
List<ConfigStruct> configurations = new ArrayList<>();
for (int i = 1; i <= 13; i++)
configurations.add(new ConfigStruct("Configuration " + i));
long startTime = System.currentTimeMillis();
new Application().runConfigurations(configurations);
System.out.println("Total time (1 thread) = " + (System.currentTimeMillis() - startTime) + " ms");
System.out.println();
startTime = System.currentTimeMillis();
new Application().runConfigurationsThreaded(configurations);
System.out.println("Total time (5 threads) = " + (System.currentTimeMillis() - startTime) + " ms");
}
}
控制臺(tái)日志將如下所示:
Executing external command: Galish full command for ConfigStruct 'Configuration 1'
Executing external command: Galish full command for ConfigStruct 'Configuration 2'
Executing external command: Galish full command for ConfigStruct 'Configuration 3'
Executing external command: Galish full command for ConfigStruct 'Configuration 4'
Executing external command: Galish full command for ConfigStruct 'Configuration 5'
Executing external command: Galish full command for ConfigStruct 'Configuration 6'
Executing external command: Galish full command for ConfigStruct 'Configuration 7'
Executing external command: Galish full command for ConfigStruct 'Configuration 8'
Executing external command: Galish full command for ConfigStruct 'Configuration 9'
Executing external command: Galish full command for ConfigStruct 'Configuration 10'
Executing external command: Galish full command for ConfigStruct 'Configuration 11'
Executing external command: Galish full command for ConfigStruct 'Configuration 12'
Executing external command: Galish full command for ConfigStruct 'Configuration 13'
Total time (1 thread) = 1374 ms
Executing external command: Galish full command for ConfigStruct 'Configuration 1'
Executing external command: Galish full command for ConfigStruct 'Configuration 2'
Executing external command: Galish full command for ConfigStruct 'Configuration 3'
Executing external command: Galish full command for ConfigStruct 'Configuration 4'
Executing external command: Galish full command for ConfigStruct 'Configuration 5'
Executing external command: Galish full command for ConfigStruct 'Configuration 6'
Executing external command: Galish full command for ConfigStruct 'Configuration 7'
Executing external command: Galish full command for ConfigStruct 'Configuration 8'
Executing external command: Galish full command for ConfigStruct 'Configuration 10'
Executing external command: Galish full command for ConfigStruct 'Configuration 9'
Executing external command: Galish full command for ConfigStruct 'Configuration 11'
Executing external command: Galish full command for ConfigStruct 'Configuration 13'
Executing external command: Galish full command for ConfigStruct 'Configuration 12'
Total time (5 threads) = 344 ms
請(qǐng)注意:
在單線程循環(huán)中運(yùn)行時(shí),運(yùn)行時(shí)間 > 1,300 毫秒 (13 x 100 毫秒)。
在具有 5 個(gè)線程的線程池中運(yùn)行時(shí),運(yùn)行時(shí)間 > 300 毫秒(3 x 100 毫秒)- 根據(jù)同時(shí)處理 5 個(gè)配置的要求,這正是您所期望的。
由于多線程,日志輸出不是直接從 1 到 13,而是有點(diǎn)不同,這里最后是 8、10、9、11、13、12。對(duì)于每個(gè)線程的不同處理時(shí)間,它看起來會(huì)更加不同。
更新:如果你想看到更多變化,只需在線程的睡眠時(shí)間中添加一個(gè)隨機(jī)元素并稍微擴(kuò)展日志記錄:
package de.scrum_master.app;
import java.io.IOException;
import java.util.Random;
public class ExternalCommandExecutor {
private static final Random RANDOM = new Random();
public static String execute(final String cmd, final String error, final boolean runInBackground, final boolean retry) throws IOException {
long sleepTime = 100 + 100 * (RANDOM.nextInt(3));
System.out.println("Executing external command: " + cmd + ", sleeping for " + sleepTime + " ms");
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Finished execution: " + cmd);
return cmd;
}
}
然后控制臺(tái)日志可能如下所示:
Executing external command: Galish full command for ConfigStruct 'Configuration 1', sleeping for 300 ms
Finished execution: Galish full command for ConfigStruct 'Configuration 1'
Executing external command: Galish full command for ConfigStruct 'Configuration 2', sleeping for 100 ms
Finished execution: Galish full command for ConfigStruct 'Configuration 2'
Executing external command: Galish full command for ConfigStruct 'Configuration 3', sleeping for 200 ms
Finished execution: Galish full command for ConfigStruct 'Configuration 3'
Executing external command: Galish full command for ConfigStruct 'Configuration 4', sleeping for 300 ms
Finished execution: Galish full command for ConfigStruct 'Configuration 4'
Executing external command: Galish full command for ConfigStruct 'Configuration 5', sleeping for 100 ms
Finished execution: Galish full command for ConfigStruct 'Configuration 5'
Executing external command: Galish full command for ConfigStruct 'Configuration 6', sleeping for 100 ms
Finished execution: Galish full command for ConfigStruct 'Configuration 6'
Executing external command: Galish full command for ConfigStruct 'Configuration 7', sleeping for 200 ms
Finished execution: Galish full command for ConfigStruct 'Configuration 7'
Executing external command: Galish full command for ConfigStruct 'Configuration 8', sleeping for 200 ms
Finished execution: Galish full command for ConfigStruct 'Configuration 8'
Executing external command: Galish full command for ConfigStruct 'Configuration 9', sleeping for 200 ms
Finished execution: Galish full command for ConfigStruct 'Configuration 9'
Executing external command: Galish full command for ConfigStruct 'Configuration 10', sleeping for 100 ms
Finished execution: Galish full command for ConfigStruct 'Configuration 10'
Executing external command: Galish full command for ConfigStruct 'Configuration 11', sleeping for 200 ms
Finished execution: Galish full command for ConfigStruct 'Configuration 11'
Executing external command: Galish full command for ConfigStruct 'Configuration 12', sleeping for 200 ms
Finished execution: Galish full command for ConfigStruct 'Configuration 12'
Executing external command: Galish full command for ConfigStruct 'Configuration 13', sleeping for 100 ms
Finished execution: Galish full command for ConfigStruct 'Configuration 13'
Total time (1 thread) = 2314 ms
Executing external command: Galish full command for ConfigStruct 'Configuration 1', sleeping for 300 ms
Executing external command: Galish full command for ConfigStruct 'Configuration 2', sleeping for 300 ms
Executing external command: Galish full command for ConfigStruct 'Configuration 3', sleeping for 200 ms
Executing external command: Galish full command for ConfigStruct 'Configuration 5', sleeping for 300 ms
Executing external command: Galish full command for ConfigStruct 'Configuration 4', sleeping for 100 ms
Finished execution: Galish full command for ConfigStruct 'Configuration 4'
Executing external command: Galish full command for ConfigStruct 'Configuration 6', sleeping for 200 ms
Finished execution: Galish full command for ConfigStruct 'Configuration 3'
Executing external command: Galish full command for ConfigStruct 'Configuration 7', sleeping for 200 ms
Finished execution: Galish full command for ConfigStruct 'Configuration 1'
Finished execution: Galish full command for ConfigStruct 'Configuration 2'
Executing external command: Galish full command for ConfigStruct 'Configuration 8', sleeping for 200 ms
Executing external command: Galish full command for ConfigStruct 'Configuration 9', sleeping for 100 ms
Finished execution: Galish full command for ConfigStruct 'Configuration 5'
Executing external command: Galish full command for ConfigStruct 'Configuration 10', sleeping for 200 ms
Finished execution: Galish full command for ConfigStruct 'Configuration 6'
Executing external command: Galish full command for ConfigStruct 'Configuration 11', sleeping for 200 ms
Finished execution: Galish full command for ConfigStruct 'Configuration 9'
Finished execution: Galish full command for ConfigStruct 'Configuration 7'
Executing external command: Galish full command for ConfigStruct 'Configuration 12', sleeping for 200 ms
Executing external command: Galish full command for ConfigStruct 'Configuration 13', sleeping for 200 ms
Finished execution: Galish full command for ConfigStruct 'Configuration 8'
Finished execution: Galish full command for ConfigStruct 'Configuration 10'
Finished execution: Galish full command for ConfigStruct 'Configuration 11'
Finished execution: Galish full command for ConfigStruct 'Configuration 13'
Finished execution: Galish full command for ConfigStruct 'Configuration 12'
Total time (5 threads) = 609 ms
看看在單線程模式下如何仍然一切都是 FIFO(先進(jìn)先出)?
另請(qǐng)注意,如果您計(jì)算控制臺(tái)上活動(dòng)(未完成)線程的數(shù)量,無論執(zhí)行時(shí)間如何,它都不會(huì)超過 5。最后 5 個(gè)線程結(jié)束。而且總執(zhí)行時(shí)間仍然明顯小于單線程情況。
更新 2:最后但同樣重要的是,如果將主循環(huán)中的元素?cái)?shù)量從 13 增加到更大的數(shù)字,比如 100,您會(huì)注意到最終多線程解決方案的總執(zhí)行時(shí)間大約為 1/單線程解決方案的5(或者一般是1除以固定線程池的線程數(shù))。這是因?yàn)榫€程除了等待并打印到控制臺(tái)外沒有做太多其他事情。如果他們實(shí)際上做了更多的事情,例如繁重的計(jì)算或大量的 I/O,那么改進(jìn)將不那么顯著,但仍然很重要。
我對(duì) 100 個(gè)配置元素的嘗試產(chǎn)生了以下輸出(縮寫):
Executing external command: Galish full command for ConfigStruct 'Configuration 1', sleeping for 300 ms
Finished execution: Galish full command for ConfigStruct 'Configuration 1'
(...)
Executing external command: Galish full command for ConfigStruct 'Configuration 100', sleeping for 300 ms
Finished execution: Galish full command for ConfigStruct 'Configuration 100'
Total time (1 thread) = 20355 ms
Executing external command: Galish full command for ConfigStruct 'Configuration 2', sleeping for 100 ms
Executing external command: Galish full command for ConfigStruct 'Configuration 1', sleeping for 300 ms
(...)
Executing external command: Galish full command for ConfigStruct 'Configuration 100', sleeping for 200 ms
Finished execution: Galish full command for ConfigStruct 'Configuration 99'
Finished execution: Galish full command for ConfigStruct 'Configuration 93'
Finished execution: Galish full command for ConfigStruct 'Configuration 94'
Finished execution: Galish full command for ConfigStruct 'Configuration 95'
Finished execution: Galish full command for ConfigStruct 'Configuration 100'
Total time (5 threads) = 3923 ms
看?~20 秒 / 5 = ~4 秒

TA貢獻(xiàn)1921條經(jīng)驗(yàn) 獲得超9個(gè)贊
在我看來你正在尋找一個(gè)java.util.concurrent.CountDownLatch
. 你給它一個(gè)數(shù)字(在你的情況下是 5)并等待一段時(shí)間讓它達(dá)到 0。谷歌會(huì)給你很多如何使用它的例子。
添加回答
舉報(bào)