同步异步任务的最佳方法

我的问题:我已经将802.15.4无线网络连接到串口(使用包装器)。 我可以将包发送到网络并监听传入的包。 你可以想象这是高度异步的。

执行任务:我想向网络发送命令并在一个函数调用中等待响应。 例如:我想从节点获取网络ID为1338的温度。

double getTemperature(int id) throws Exception { .... } 

除了执行所有这些“同步(对象)等待(…)通知(..)”之外​​,还有更好的方法来等待响应消息吗?

最好的问候,bigbohne

也许添加一些香料:

这应该都以Web界面结束,用户可以通过ajax或直接请求这些命令。 我还想过在数据库中缓存响应值。 但是对于某些命令,你MUSS可以直接回答成功/失败

您可以使用BlockingQueue执行此操作,这样您就不必手动管理任何同步。 请求可以发送消息,然后在BlockingQueue上调用take(),它将等待元素出现。 该元素是在返回回复时由端口上的任何侦听器插入到队列中的回复。

您只需要进行协调,以便侦听器和请求者共享同一个队列。 对于支持此方案的每个请求,您只需要一个大小为1的队列。

 // Send method BlockingQueue q = new ArrayBlockingQueue(1); serialCom.registerQueue(myRequest.getId()); serialCom.sendRequest(myRequest); return q.take(); //Listener BlockingQueue q = queueMap.get(incomingMessage.getId()); q.add(incomingMessage.getReply()); 

我不确定我是否正确地理解了这个问题,但我通常使用Future来完成这些任务。

在内部, Future实现使用wait和notify以及所有这些,但接口本身变得相当干净。

 Future getTemperature(int id); 

在您的通信代码中,您可以将传入的消息映射到未实现的未来。 如果保证订购,您可以做类似的事情

 class Something { Map> requests; synchronized Future request(int id, Object data) { MyFutureImpl future = new MyFuture(); requests.get(id).add(future); serializeAndSend(id, data); return future; } void serializeAndSend(id, data) {...} synchronized void response(int id, Object data) { MyFutureImpl future = requests.get(id).remove(); future.setValue(data); // This would fulfill the future, and any // threads waiting in a get() will get the // value and continue. } } 

MyFutureImpl是一个非常基本的未来实现。 我假设有一个通信线程在收到数据包时调用response() 。 我还假设serializeAndSend()函数处理对客户端或块的写入,直到可以进行写操作或将其传递给通信线程。

使用具有并发能力的映射和队列结构可能会使某些synchronization变得不必要。 如果每个id只有一个未完成的呼叫,那么队列当然就变得不必要了。

更好的方法是将其包装在一些可重用的请求/响应类中。 这样,您可以使用标准方法查询串行端口并等待响应。 但是,这个类无疑必须在其实现的某个地方使用synchronized关键字和wait和notify命令。 这是编写Java的关键部分,了解它们的工作原理非常重要。

如果你要设计一个像你说的那样的函数,你必须确保从一个可以阻止等待结果的线程中调用它。 该函数必须在其中实现某种等待来自串行端口的响应的等待循环。 因此,无论运行什么线程都能够等待,这一点非常重要。

这确实提出了一个额外的观点。 如果您有多个线程执行此操作,您将需要一些处理串行端口通信的类,该类可以处理来自多个线程的多个请求,并根据需要对它们进行排队以处理串行端口和特定设备的异步性质你要连接的。 例如,在完全读取第一个命令之前发送第二个命令可能不合适。

这里有几个复杂的问题,重要的是要有一个好的设计,以合理的方式解决所有这些问题。