仅当主监听器更新时,如何将来自主 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 与线程内的新变量同步的主要内容,如果未能解决你的问题,请参考以下文章
仅当有更新时,如何使用 GDI 读取 Windows 屏幕部分?