Как заставить асинхронный слушатель делать блокировку? - PullRequest
2 голосов
/ 23 января 2012

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

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

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

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

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

Спасибо

Я должен также добавить всплывающие уведомления notifyAll с исключением 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 ]

2 голосов
/ 23 января 2012

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

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

0 голосов
/ 24 января 2012

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

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

private final Object resultLock = new Object();

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

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

0 голосов
/ 23 января 2012

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

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

...