Как заставить асинхронный слушатель делать блокировку?

Я пишу приложение для BlackBerry, которое взаимодействует с простым периферийным устройством Bluetooth с помощью текстовых AT-команд - по аналогии с модемом... Я могу заставить его работать на BlackBerry только с помощью прослушивателя событий. Таким образом, связь теперь асинхронная.

Однако, поскольку это простое устройство, и мне нужно управлять одновременным доступом, я бы предпочел просто блокирующий вызов.

У меня есть следующий код, который пытается преобразовать сообщения в блокировку с помощью ожидания / уведомления. Но когда я его запускаю, notifyResults никогда не запускается до тех пор, пока getStringValue не завершится. т.е. он всегда будет вне зависимости от времени задержки.

Объект btCon уже работает в отдельном потоке.

Я уверен, что я пропускаю что-то очевидное с многопоточностью. Может ли кто-нибудь любезно указать на это?

Спасибо

Я также должен добавить всплывающее уведомление noAllAllException с помощью IllegalMonitorStateException.

Ранее я пробовал это с простым логическим флагом и циклом ожидания. Но та же проблема существовала. 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
        }
    }

}

3 ответа

Поскольку и notifyResults, и getStringValue имеют синхронизированные предложения для одного и того же объекта, при условии, что getStringValues ​​попадает в синхронизированный раздел, сначала notifyResults будет блокироваться в начале синхронизированного предложения до тех пор, пока getStringValues ​​не выйдет из синхронизированной области. Если я понимаю, это поведение, которое вы видите.

Совет Николаса, вероятно, хорош, но вы можете не найти ни одной из этих реализаций в используемых вами API-интерфейсах BlackBerry. Возможно, вы захотите взглянуть на модель продукта-потребителя.

Может быть более целесообразно использовать Latch, Semaphore или Barrier, как рекомендует Брайан Гетц, книга Java Concurrency in Practice.

Эти классы облегчат написание методов блокировки и, вероятно, помогут предотвратить ошибки, особенно если вы не знакомы с wait() а также notifyAll(), (Я не говорю, что вы незнакомы, это просто примечание для других...)

Код будет работать нормально. Если вы будете использовать конечный объект вместо строковой переменной. Я удивлен, что вы не получаете NPE или IMSE.

Создать поле:

private final Object resultLock = new Object();

Измените все синхронизированные разделы, чтобы использовать его вместо строкового поля result,

Мне не нравится магическое число 5 сек. Я надеюсь, что вы рассматриваете нулевой результат как тайм-аут в вашем приложении.

Другие вопросы по тегам