Как синхронизировать MesageReceivedEvent из основного EventListener с новой переменной внутри Thread, только когда она обновляется слушателем main - PullRequest
0 голосов
/ 20 сентября 2019

Мне нужно создать новый поток, который будет выполнять метод тогда и только тогда, когда MessageReceivedEvent обновляется внутри основного ListenerAdapter, и позволять потоку спать, когда переменная не обновляется.Этот поток должен работать независимо от основного потока и не останавливать новые запросы.

Это класс потока,

private static final class Worker extends Thread {

        private volatile boolean running = false;
MessageReceivedEvent event; //this must update along with the listener

        private boolean validateData() {
            if (//something) {
                return true;
            }
            return false;
        }

        private void waitForInput() {

            boolean hasInput = false;
            try {
                while (!hasInput) {
                    hasInput = validateData();
                    if (!hasInput) {

                        Thread.sleep(10);

                    }
                }
            } catch (InterruptedException iex) {
                Thread.currentThread().interrupt();
            }
        }

        @Override
        public void run() {
            running = true;
            while (running) {
                waitForInput();

                //do something

            }

        }

    }

Это внутренний класс, запускаемый запросом из основного потока,MessageReceivedEvent внутри него должен обновляться только при изменении фактического события от слушателя, в противном случае он ничего не должен делать.При тестировании он будет выполняться только на основе MessageEvent, вызвавшего поток. Как я могу заставить этот поток получать обновления?

public class Listener extends ListenerAdapter {

    public static MessageReceivedEvent msgEvnt;


    @Override
    public void onMessageReceived(MessageReceivedEvent msgEvnt) {

                    Listener.msgEvnt = msgEvnt;
    }

Это все, что делает слушатель, обновляет переменную всякий раз, когда появляется новыйMessageEvent.

1 Ответ

1 голос
/ 20 сентября 2019

Для этого можно использовать Условную переменную .

final ReentrantLock lock = new ReentrantLock();
final Condition condition = lock.newCondition();

private void waitForInput() {
    lock.lock();
    Listener.msgEvnt = null;
    try {
        while (Listener.msgEvnt == null)
            condition.await();
    } catch (InterruptedException e) {
        e.printStackTrace();
    } finally {
        lock.unlock();
    }
}

@Override
public void onMessageReceived(MessageReceivedEvent event) {
    lock.lock();
    try {
        Listener.msgEvnt = msgEvnt;
        condition.signal();
    } finally {
        lock.unlock();
    }
}

См. ReentrantLock и Условие


Вы можете использовать BlockingQueue

final BlockingQueue queue = new ConcurrentBlockingQueue();

private MessageReceivedEvent waitForInput() throws InterruptedException {
    return queue.take();
}

@Override
public void onMessageReceived(MessageReceivedEvent event) {
    queue.put(event);
}

Вы можете использовать Callback , это то, что я бы порекомендовал.

Consumer<? super MessageReceivedEvent> callback;

private void onInput(Consumer<? super MessageReceivedEvent> callback) {
    this.callback = callback;
}

@Override
public void onMessageReceived(MessageReceivedEvent event) {
    if (this.callback != null)
        this.callback.accept(event);
    this.callback = null;
}

Пример использования:

listener.waitForInput(event -> {
    System.out.printf("%#s: %s\n", event.getAuthor(), event.getMessage().getContentDisplay());
});

Это уже предоставлено JDA-Utilities

...