如何与父线程通信已经调用了一个监听器?

时间:2012-03-20 21:49:34

标签: java synchronization listener wait notify

我想知道一个监听器应该如何让父线程知道它已被调用。 (基本上我试图强制异步调用是同步的。)我的例子包括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,虽然它在实际代码中。)通常,我在两个线程之间进行通信时也会有一个标志,但是我不能为此目的使用局部变量,因为它必须是最终才能从匿名类访问,并且实例变量看起来像是违反抽象(并且必须是易失性的)。

上述代码是否安全和/或是否有更好的方法来解决问题?

2 个答案:

答案 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