【问题标题】:How to make an async listener do blocking?如何使异步侦听器进行阻塞?
【发布时间】:2012-02-17 01:01:23
【问题描述】:

我正在编写一个黑莓应用程序,该应用程序使用基于文本的 AT 命令与简单的蓝牙外围设备进行通信——类似于调制解调器......我只能使用事件侦听器让它在黑莓上工作。所以现在通信是异步的。

但是,由于它是一个简单的设备,并且我需要控制并发访问,我宁愿只进行阻塞调用。

我有以下代码尝试通过使用等待/通知将通信转换为阻塞。但是当我运行它时, notifyResults 在 getStringValue 完成之前永远不会运行。即,无论延迟如何,它总是会超时。

btCon 对象已经在单独的线程上运行。

我确定我在线程方面遗漏了一些明显的东西。有人能指出来吗?

谢谢

我还应该添加带有 IllegalMonitorStateException 的 notifyAll。

我之前尝试过使用简单的布尔标志和等待循环。但同样的问题也存在。 notifyResult 在 getStringValue 完成之前永远不会运行。

public class BTCommand implements ResultListener{
    String cmd;
    private BluetoothClient btCon;
    private String result;

    public BTCommand (String cmd){
        this.cmd=cmd;
        btCon = BluetoothClient.getInstance();
        btCon.addListener(this);

        System.out.println("[BTCL] BTCommand init");
    }

    public String getStringValue(){
        result = "TIMEOUT";
        btCon.sendCommand(cmd);
        System.out.println("[BTCL] BTCommand getStringValue sent and waiting");

        synchronized (result){
            try {
                result.wait(5000);
            } catch (InterruptedException e) {
                System.out.println("[BTCL] BTCommand getStringValue interrupted");
            }
        }//sync
        System.out.println("[BTCL] BTCommand getStringValue result="+result);

        return result;
    }

    public void notifyResults(String cmd) {
        if(cmd.equalsIgnoreCase(this.cmd)){
            synchronized(result){
                result = btCon.getHash(cmd);
                System.out.println("[BTCL] BTCommand resultReady: "+cmd+"="+result);                
                result.notifyAll();
            }//sync
        }
    }

}

【问题讨论】:

    标签: java blackberry java-me bluetooth iobluetooth


    【解决方案1】:

    按照Brian Goetz book Java Concurrency in Practice 的建议,使用LatchSemaphoreBarrier 可能更合适。

    这些类将使编写阻塞方法更容易,并且可能有助于防止错误,特别是如果您不熟悉wait()notifyAll()。 (我并不是说不熟悉,只是给别人的一个注解……)

    【讨论】:

    • 我还应该添加 notifyAll 因 IllegalMonitorStateException 而爆炸。我之前用一个简单的布尔标志和一个等待循环尝试过。但同样的问题也存在。 notifyResult 在 getStringValue 完成之前永远不会运行。
    • 对于这种情况,我使用布尔标志和等待循环,就像您尝试的那样,在该循环中使用 Thread.sleep()。而且我不使用任何信号量。但不确定为什么您的解决方案不起作用。
    【解决方案2】:

    由于 notifyResults 和 getStringValue 在同一个对象上都有同步子句,假设 getStringValues 首先到达同步部分,notifyResults 将在同步子句开始处阻塞,直到 getStringValues 退出同步区域。如果我理解,这就是您所看到的行为。

    Nicholas 的建议可能不错,但您可能在您使用的 BlackBerry API 中找不到任何这些实现​​。您可能想看看produce-consumer 模式。

    【讨论】:

      【解决方案3】:

      代码可以正常工作。如果您将使用最终对象而不是字符串变量。我很惊讶您没有获得 NPE 或 IMSE。

      创建字段:

      private final Object resultLock = new Object();
      

      更改所有同步部分以使用它而不是字符串字段result

      我不喜欢魔法数字 5 秒。我希望您在应用程序中将 null 结果视为超时。

      【讨论】:

        猜你喜欢
        • 2015-11-06
        • 1970-01-01
        • 2014-07-19
        • 1970-01-01
        • 2018-04-06
        • 1970-01-01
        • 2020-11-09
        • 1970-01-01
        • 2016-07-14
        相关资源
        最近更新 更多