仅当主监听器更新时,如何将来自主 EventListener 的 MesageReceivedEvent 与线程内的新变量同步

Posted

技术标签:

【中文标题】仅当主监听器更新时,如何将来自主 EventListener 的 MesageReceivedEvent 与线程内的新变量同步【英文标题】:How to synchronize MesageReceivedEvent from main EventListener with a new variable inside Thread only when it is updated by main's listener 【发布时间】:2020-01-21 04:39:56 【问题描述】:

我需要创建一个新线程,当且仅当在主 ListenerAdapter 中更新 MessageReceivedEvent 时才会执行一个方法,并在变量未更新时让线程休眠。 该线程应该独立于主线程运行,并且不会停止新的请求。

这是线程类,

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;
    

这就是监听器所做的一切,每当有新的消息事件时更新变量。

【问题讨论】:

您是否绝对需要将该事件保留为您的线程的成员?如果没有,您可以使用 BlockingQueue 来处理您的事件。您的主线程可以将事件放入队列中,而您的专用线程将阻塞,直到使用方法 take() docs.oracle.com/javase/7/docs/api/java/util/concurrent/… 将某些元素放入队列中 【参考方案1】:

您可以使用Condition Variable 来完成此操作。

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和Condition


您可以使用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提供

【讨论】:

以上是关于仅当主监听器更新时,如何将来自主 EventListener 的 MesageReceivedEvent 与线程内的新变量同步的主要内容,如果未能解决你的问题,请参考以下文章

仅当他们有电话号码时,如何获取所有联系人的全名和电话号码?

SaltStack:仅当目录存在时才使用目录作为源

仅当有更新时,如何使用 GDI 读取 Windows 屏幕部分?

仅当更新前不存在用户时如何将用户添加到索引 Elasticsearch

仅当我在主应用程序中按下活动中的按钮时,如何更新小部件

仅当应用程序处于前台而不是通知中时,如何捕获辅助功能事件?