Java Регулируемая «Потребительская» нить - PullRequest
0 голосов
/ 05 мая 2020

Я пытаюсь создать очередь задач, которая запускается только один раз каждые throttle миллисекунды, пока в очереди есть задачи. Кроме того, поскольку задачи создают онлайн-запросы, мне нужно запускать их в другом потоке, чтобы не замедлить работу остальной части приложения. Данные, которые я получаю, не являются «высокоприоритетными», и мне не нужно быстро проходить через очередь, поскольку я хочу, чтобы скорость запроса была минимальной. Я попробовал следующий код, хотя был почти уверен, что он не сработает:

public class QueryManager implements Runnable {
    private Plugin p;
    private ScheduledExecutorService executor;
    private ConcurrentLinkedQueue<QueryRequest> jobs;

    public QueryManager(Plugin p) {
        this.p = p;
        this.executor = Executors.newSingleThreadScheduledExecutor();
        this.jobs = new ConcurrentLinkedQueue<>();
        this.executor.schedule(
                this,
                p.getConfig().getInt("requestThrottle", 250), //the int is used as default
                TimeUnit.MILLISECONDS);
    }

    public void addJob(QueryRequest req) {
        this.jobs.add(req);
        this.notify();
    }

    @Override
    public void run() {
        QueryRequest req = this.jobs.poll();
        if (req == null) {
            try {
                this.wait();
            } catch (Exception e) { e.printStackTrace(); }
        }
        else {
            req.run();
        }
    }
}

Как и ожидалось, это приводит к IllegalMonitorStateException. Я не разбираюсь в многопоточности и понятия не имею, как еще попытаться здесь достичь своей цели. (Потребитель указан в кавычках в названии, потому что он действует как потребитель, но я не уверен, является ли он технически потребителем.) чтобы сделать его работоспособным, но это не соответствует моим предпочтениям по производительности при паузе, когда в очереди нет элемента.

    //...snip...
    public void addJob(QueryRequest req) {
        this.jobs.add(req);
    }

    @Override
    public void run() {
        QueryRequest req = this.jobs.poll();
        if (req != null) {
            req.run();
        }
    }
}

Ответы [ 2 ]

0 голосов
/ 06 мая 2020

Следующий код не содержит ошибок, но выполняет только одно задание из списка:

public class QueryManager implements Runnable {
    private Plugin p;
    private ScheduledExecutorService executor;
    private ConcurrentLinkedQueue<QueryRequest> jobs;

    public QueryManager(Plugin p) {
        this.p = p;
        this.executor = Executors.newSingleThreadScheduledExecutor();
        this.jobs = new ConcurrentLinkedQueue<>();
        int throttle = Math.max(p.getConfig().getInt("requestThrottle", 250), 200);
        this.executor.schedule(this, throttle , TimeUnit.MILLISECONDS);
        Verbose.debug("Request throttle set to ", Integer.toString(throttle), TimeUnit.MILLISECONDS.name());
    }

    public void addJob(QueryRequest req) {
        this.jobs.add(req);
        Verbose.debug("Added query task to queue: ", req.getName());
    }

    @Override
    public void run() {
        QueryRequest req = this.jobs.poll();
        if (req != null) {
            Verbose.debug("Processing job...");
            req.run();
        }
    }
}

Он все еще не работает, однако теперь, когда у него совершенно другая проблема, я думаю, что это лучше всего подходит как совершенно другой вопрос. Для некоторой преемственности я отредактирую ссылку на этот вопрос после его публикации. Изменить: новый вопрос Java "Ограниченный потребитель" запускается только один раз

0 голосов
/ 05 мая 2020

Что вам вероятно действительно нужно, так это переборка , но чтобы сделать это самостоятельно, вам просто нужно исправить метод run, чтобы он возвращался немедленно, если у вас нет ожидающих запросов. Задача исполнителя - вызывать run несколько раз по расписанию.

Обратите внимание, что если вы управляете своим собственным исполнителем, у вас должен быть метод shutdown(), который аккуратно его завершает; в среде контейнера этот метод должен быть аннотирован @PreDestroy.

...