我需要运行五个线程来每隔20秒从API重复获取数据,所以我使用了ScheduledExecutorService。
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(5);
for (int i = 0; i < 5; i++) {
scheduler.scheduleWithFixedDelay(Constant.workerThread[i], 0, delay, TimeUnit.SECONDS);
}
我怎么知道(每次)执行五个线程的时间?
答案 0 :(得分:2)
编辑:看来人们并没有真正理解代码段的想法。我将其设置为大胆,以便没有人再出现在我面前,从外部(而不是在shell_exec("php slow_request.php '".$parameter.”’ > /dev/null &");
lambda内部)管理内部ExecutorService
,并在需要时采取适当的措施使其有序地关闭< / strong>。
您可以做的是管理一个预定的任务,然后在其中执行五个工作人员。
Callable
JavaDoc for final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(5);
scheduler.scheduleWithFixedDelay(
() -> {
final ExecutorService e = Executors.newFixedThreadPool(5);
final CompletionService<?> cs = new ExecutorCompletionService<>(e);
for (int i = 0; i < 5; i++) {
// Constant.workerThread[i] is a Runnable
cs.submit(Constant.workerThread[i], null);
}
for (int i = 0; i < 5; i++) {
try {
// Will block until a Future<?> result is available.
// Doesn't matter which one, it will take the first available.
cs.take();
} catch (final InterruptedException ignored) {
// Ingore the exception, as we care only
// about if all off them finished (abruptly or not)
}
}
// All of them finished!
e.shutdown();
}, 0, 20, TimeUnit.SECONDS));
使用提供的
ExecutorCompletionService
执行的CompletionService
任务。此类安排提交的任务完成后, 放在使用Executor
可以访问的队列中。
JavaDoc for take
检索并删除代表下一个完成的
ExecutorCompletionService#take
任务,等待是否还没有出现。
这必须加以改进,但是您应该明白这一点。
答案 1 :(得分:1)
Runnable
个对象,而不是线程线程没有被“执行”。
您应将Runnable
传递给ScheduledExecutorService::scheduleAtFixdDelay
。我对您的命名Constant.workerThread
感到担心。您没有传递线程,而是传递了要在某个线程上运行的任务。您不必担心哪个线程运行什么Runnable
任务。您根本不需要关心线程。处理要在线程上运行的任务是执行程序的工作,因此是名称。
您似乎缺少线程和任务的基本概念。毫不奇怪,因为它刚开始时是一个棘手的主题。我建议研究Oracle.com免费提供的有关线程和执行程序的Java教程。然后进行一些互联网搜索以了解更多信息。最终,您应该学习Brian Goetz等人的著作《 Java Concurrency In Practice》。
。ScheduledFuture
跟踪完成情况因此,您将不会监视线程。而是专注于您的Runnable
任务。要监视它们的状态,请通过调用ScheduledFuture
来捕获scheduleAtFixedDelay
对象返回。当前,您正在忽略那些返回的对象。
该计划的将来对象提供了一些方法来查看任务是否完成或取消。您也可以取消任务。
答案 2 :(得分:1)
如果您可以更改计划任务的源代码,则可以实现以下内容:
public class ScheduleExample {
private static ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(5);
static abstract class RunnableWithNotification implements Runnable {
@Override
public final void run() {
beforeRun();
doRun();
afterRun();
}
public abstract void doRun();
public abstract void beforeRun();
public abstract void afterRun();
}
public static void main(String... args) {
long delay = 5;
List<Runnable> tasks = Arrays.asList(
newRunnableWithNotification(1),
newRunnableWithNotification(2),
newRunnableWithNotification(3),
newRunnableWithNotification(4),
newRunnableWithNotification(5));
tasks.forEach(task -> scheduler.scheduleWithFixedDelay(task, 0, delay, TimeUnit.SECONDS));
}
private static Runnable newRunnableWithNotification(int i) {
return new RunnableWithNotification() {
@Override
public void doRun() {
System.out.println("Executing task " + i);
}
@Override
public void beforeRun() {
System.out.println("Before executing task " + i);
}
@Override
public void afterRun() {
System.out.println("After executed task " + i);
}
};
}
}
答案 3 :(得分:0)
您可以设置一种执行映射。
关于每个可运行对象的执行状态的总是最新数据。
这是一个一般示例,因此您需要使其适应您的需求。
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class Application {
// Your mocked runnables
private static List<Runnable> workerRunnables = new ArrayList<>();
// This will be the map with always updated values, get the map at[i]
// will return if workerThread[i is running]
private static Map<Integer, Boolean> executionMap = new ConcurrentHashMap<>();
private static final int threadPoolSize = 5;
public static void main(String[] args) {
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(threadPoolSize);
for (int i = 0; i < threadPoolSize; i++) {
int finalI = i;
workerRunnables.add(() -> {
try {
// Update the map, the runnable has started
executionMap.put(finalI, true);
// Simulating your API calls with different types of delay
Thread.sleep(3000);
if (finalI == 2) {
Thread.sleep(1000);
}
// Update the map, the runnable has finished
executionMap.put(finalI, false);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
workerRunnables.forEach(worker -> scheduler.scheduleWithFixedDelay(worker, 0, 2, TimeUnit.SECONDS));
Executors.newCachedThreadPool().execute(new Runnable() {
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
@Override
public void run() {
scheduler.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
for (int i = 0; i < threadPoolSize; i++) {
System.out.println("Runnable number " + i +" is running: " + executionMap.get(i));
}
}
}, 0, 2, TimeUnit.SECONDS);
}
});
}
}