Java中的并发 - 将任务委派给工作线程,我做得对吗?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java中的并发 - 将任务委派给工作线程,我做得对吗?相关的知识,希望对你有一定的参考价值。
所以我正在为一个在线游戏制作一个模拟器,我似乎无法想出一个很好的方法来处理同时运行的大量任务。显然,在一个线程上加载所有内容都不起作用。
我的想法是有一个主线程将任务委托给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;
}
}
我的问题如下:
- 在Engine类中,在并发性方面使用常规ArrayList是否可以?
- 有没有更好的方法将任务排队到ExecutorService?如果有太多任务同时排队,我觉得它可能会导致问题。
- 在我开始重新发明轮子之前,是否有任何我应该关注的引擎框架?
如果您担心可能在ExecutorService
中排队太多任务,可以使用Semaphore
来限制它一次可以运行的任务。
将它放在你的processQueuedTasks()
方法for循环中,以限制要运行的任务数量。
https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Semaphore.html
您可以设置线程池中的线程数,而不是使用Semaphore
来限制并发运行的任务数。您将只获得与线程同时运行的任务数
Executors.newFixedThreadPool(n);
public void queueTask(Task task) {
由于此方法是公共的,因此可以从任何线程调用它,因此ArrayList
不会是线程安全的。想想如果您在将任务提交给执行程序期间尝试对任务进行排队,会发生什么。您已从线程池执行程序“借用”了功能,并通过拥有任务集合将其放入代码中。
以上是关于Java中的并发 - 将任务委派给工作线程,我做得对吗?的主要内容,如果未能解决你的问题,请参考以下文章