我对如何进行代码有疑问。我的项目是在后台逐个运行配置的工具。我想为运行配置的数量增加一个限制。例如,如果我有13种配置,我想每次都运行5种配置,因此顺序为:
- Running 5 configurations
- All 5 configurations done running
- Running 5 configurations
- All 5 configurations done running
- Running 3 configurations
- All 3 configurations done running
Run Code Online (Sandbox Code Playgroud)
现在的代码如下:
public void runConfigurations(List<ConfigStruct> configurations) {
for (ConfigStruct configuration : configurations) {
try {
configuration.run();
} catch (ConfigurationException e) {
continue;
}
}
}
Run Code Online (Sandbox Code Playgroud)
目前,它逐个运行每种配置。该run方法如下所示:
public void run() throws ConfigurationException {
StringBuffer runCmd = generateGalishFullCommand(GalishFlags.RUN);
try {
ExternalCommandExecutor.execute(runCmd, "Failed to run " + name, true, true);
} catch (IOException e) {
throw new ConfigurationException(e.getMessage());
}
}
Run Code Online (Sandbox Code Playgroud)
execute外观的签名如下:
public static String execute(final String cmd, final String error, final boolean runInBackground, final boolean retry) throws IOException;
Run Code Online (Sandbox Code Playgroud)
首先,我虽然可以每5个配置运行最后一个配置,但不是在后台运行,而是有问题的。我不能在后台每5个配置都不执行最后一个配置,因为第一个配置可能最后执行一次。我该如何解决这个问题?
编辑:
当我打印配置时,它看起来如下:
[com.configStructs@3f15dbec, com.configStructs@31d2327e]
Run Code Online (Sandbox Code Playgroud)
另外,configurations是的列表configStructs。
对不起,如果我没有完全理解甚至误解您的问题,那么vesii,但您的英语不是很好,即使您发表评论以查看使用多线程的问题所在,我也有问题。
无论如何,我建议您让您的ConfigStruct类实现该Runnable接口,这很容易,因为它已经有一个run()方法。你只需要摆脱抛出检查异常,所以我建议进一步做ConfigurationException一个RuntimeException你不必在方法签名声明。
不幸的是,您没有提供完整的MCVE,仅提供了代码片段。因此,我必须弥补其余部分,以便能够编译和运行您的代码。我刚刚添加了一些简单的帮助程序/虚拟类。我的解决方案如下所示:
package de.scrum_master.app;
public enum GalishFlags {
RUN
}
Run Code Online (Sandbox Code Playgroud)
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);
}
}
Run Code Online (Sandbox Code Playgroud)
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;
}
}
Run Code Online (Sandbox Code Playgroud)
如您所见,命令执行程序在将某些内容打印到控制台后等待100毫秒。如果您想让程序运行得更慢甚至随机化,以模拟需要不同时间才能完成的命令,也可以将其更改为1000 ms。
现在,我们需要一个小的驱动程序应用程序,在其中生成配置并运行它们。解决的绝不会在同一时间运行超过5个线程你的问题的关键是建立一个固定的线程池通过Executors.newFixedThreadPool(5)。其余的应该很容易理解。
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 + "'");
}
}
Run Code Online (Sandbox Code Playgroud)
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");
}
}
Run Code Online (Sandbox Code Playgroud)
控制台日志将如下所示:
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
Run Code Online (Sandbox Code Playgroud)
请注意:
更新:如果您希望看到更多变化,只需在线程的睡眠时间中添加一个随机元素,然后将日志记录扩展一点:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
然后,控制台日志可能如下所示:
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
Run Code Online (Sandbox Code Playgroud)
看看在单线程模式下,什么仍然是FIFO(先进先出)?
另请注意,如果您在控制台上计算活动(未完成)线程的数量,则无论执行时间如何,它的数量永远不会超过5。最后,最后5个线程结束。而且总的执行时间仍然明显小于单线程情况。
更新2:最后但并非最不重要的一点是,如果将主循环中的元素数量从13个增加到更大的数量(例如100个),您将注意到最终多线程解决方案的总执行时间约为1 / 5个(或通常1除以固定线程池中的线程数)的单线程解决方案。这是因为线程没有做其他事情,而是等待并打印到控制台。如果他们实际上做了更多的事情,例如繁重的计算或大量的I / O,那么改进将不会那么显着,但仍然很有意义。
我尝试使用100个配置元素产生了以下输出(缩写):
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
Run Code Online (Sandbox Code Playgroud)
看到?〜20秒/ 5 =〜4秒