所以我正在为在线游戏制作模拟器,我似乎无法想出一个很好的方法来处理同时运行的大量任务。显然,在一个线程上加载所有内容都不起作用。
我的想法是有一个主线程将任务委托给x个工作线程。一旦主线程完成排队任务,它就会发信号通知工人开始解雇任务并停止,直到他们完成。我的实现如下:
package com.rs2.engine;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.CountDownLatch;
import java.util.ArrayList;
import com.rs2.util.Timer;
public class Engine implements Runnable {
private ScheduledExecutorService scheduledExecutorService;
private ExecutorService executorService;
private int currentTick;
private ArrayList<Task> tasks;
private Timer timer;
public Engine(int workers) {
this.executorService = Executors.newFixedThreadPool(workers);
this.scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
this.currentTick = 0;
this.tasks = new ArrayList<>(10000);
this.timer = new Timer();
}
public int getCurrentTick() {
return currentTick;
}
public ExecutorService getWorkers() {
return executorService;
}
public void start() {
this.scheduledExecutorService.scheduleAtFixedRate(this, 0, 600, TimeUnit.MILLISECONDS);
}
public void cycle() {
}
public void queueTask(Task task) {
tasks.add(task);
}
public void processQueuedTasks() {
try {
CountDownLatch latch = new CountDownLatch(tasks.size());
for (int i = 0; i < tasks.size(); i++) {
Task t = tasks.get(i);
t.setCountDownLatch(latch);
executorService.submit(t);
}
latch.await();
tasks.clear();
} catch(Exception e) {
e.printStackTrace();
}
}
@Override
public void run() {
timer.reset();
cycle();
currentTick++;
//System.out.println("Cycle time: "+timer.elapsed());
}
}
仅从主线程调用queueTask()和 processQueuedTasks()。此引擎用于处理服务器需要执行的任何和所有任务。首先,它处理网络事件(传入的数据包),然后更新实体和其他事件。这就是为什么我喜欢把它抽象化。
以下是Task类:
package com.rs2.engine;
import java.util.concurrent.CountDownLatch;
public class Task implements Runnable {
private CountDownLatch latch;
public Task() {
}
@Override
public void run() {
execute();
latch.countDown();
}
public void execute() {
}
public void setCountDownLatch(CountDownLatch latch) {
this.latch = latch;
}
}
我的问题如下:
答案 0 :(得分:0)
如果您担心可能在ExecutorService
中排队太多任务,可以使用Semaphore
来限制一次可以运行的任务。
将它放在processQueuedTasks()
循环方法中,以限制要运行的任务数。
https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Semaphore.html
答案 1 :(得分:0)
您可以设置线程池中的线程数,而不是使用Semaphore
来限制并发运行的任务数。您将只获得与线程同时运行的任务数
Executors.newFixedThreadPool(n);
public void queueTask(Task task) {
由于此方法是公共的,因此可以从任何线程调用它,因此ArrayList
不是线程安全的。想想如果您在将任务提交给执行程序期间尝试对任务进行排队,会发生什么。您已从线程池执行程序“借用”了功能,并通过拥有任务集合将其放入代码中。