我想知道一个监听器应该如何让父线程知道它已被调用。 (基本上我试图强制异步调用是同步的。)我的例子包括Android调用,但它更像是一般的同步问题......
方法myMethod()请求SoundPool加载声音并在调用完成时通知侦听器。我希望myMethod()等到监听器被调用后再返回。我想出的代码是:
void myMethod() {
SoundPool soundPool = ...;
final Lock object = new Object();
soundPool.setOnLoadCompleteListener(new OnLoadCompleteListener(){
@Override
public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
synchronized(lock) {
lock.notify();
}
}});
synchronized(lock) {
int soundId = MediaUtil.loadSoundPool(soundPool, ...); // returns immediately
lock.wait();
}
}
(为了简单起见,我省略了try / catch,虽然它在实际代码中。)通常,我在两个线程之间进行通信时也会有一个标志,但是我不能为此目的使用局部变量,因为它必须是最终才能从匿名类访问,并且实例变量看起来像是违反抽象(并且必须是易失性的)。
上述代码是否安全和/或是否有更好的方法来解决问题?
答案 0 :(得分:2)
许多选项可以满足您的需求。这是使用wait / notify执行此操作的一种方法。 isNotified用于防止在调用setListener()的同一线程调用onLoadComplete()的情况下挂起。当您查看来自大型应用程序的线程转储时,MonitorXX类可以使调试更容易。根据需要添加错误/异常/ timeOut检查。
static class Monitor42{boolean isNotified=false;}
static Monitor42 monitor = new Monitor42();
void myMethod() {
synchronized(monitor) {
monitor.isNotified=false;
xxx.setListener(new Listener(){
public void onLoadComplete() {
synchronized(monitor) {
monitor.isNotified=true;
monitor.notify();
}
}});
if (!monitor.isNotified) monitor.wait(someTimeValueMS);
monitor.isNotified=false;
}
}
答案 1 :(得分:1)
基本上我试图强制异步调用是同步的。
执行此操作的规范方法正是您正在执行的操作:在后台线程中异步工作结束时触发通知并等待主线程中的通知。
但是我不能为此目的使用局部变量,因为它必须是最终可以从匿名类访问
绕过此限制的简单方法是使用final Boolean[] flag = new Boolean[1]; flag[0] = false
。