Java中的并发 - 将任务委派给工作线程,我做得对吗?

时间:2018-03-03 11:06:34

标签: java concurrency executorservice

所以我正在为在线游戏制作模拟器,我似乎无法想出一个很好的方法来处理同时运行的大量任务。显然,在一个线程上加载所有内容都不起作用。

我的想法是有一个主线程将任务委托给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;
    }

}

我的问题如下:

  1. 在Engine类中,在并发性方面使用常规ArrayList是否可以?
  2. 有没有更好的方法将任务排队到ExecutorService?如果有太多任务同时排队等候,我觉得这可能会导致问题。
  3. 在我开始重新发明轮子之前,是否有任何我应该看的引擎框架?

2 个答案:

答案 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不是线程安全的。想想如果您在将任务提交给执行程序期间尝试对任务进行排队,会发生什么。您已从线程池执行程序“借用”了功能,并通过拥有任务集合将其放入代码中。