Как заставить асинхронный слушатель делать блокировку?
Я пишу приложение для 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 сек. Я надеюсь, что вы рассматриваете нулевой результат как тайм-аут в вашем приложении.