java 同步异步任务的最佳方式
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3855393/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Best way to synchronize asynchronous task
提问by Bigbohne
My Problem: I've got 802.15.4 Wireless network connected to a serial port (using a wrapper). I can send packages into the network and listen for incoming packages. As you can imagine this is highly asynchronous.
我的问题:我将 802.15.4 无线网络连接到串行端口(使用包装器)。我可以将包裹发送到网络并监听传入的包裹。可以想象,这是高度异步的。
Here comes the task: I want to send commands to the network and wait for the response in one function call. For Example: I want to get the temperature from the Node with the network ID 1338.
任务来了:我想向网络发送命令并在一个函数调用中等待响应。例如:我想从网络 ID 为 1338 的节点获取温度。
double getTemperature(int id) throws Exception { .... }
Is there a better way of waiting for a response message other than doing all this "synchonized(object) wait(..) notify(..)" stuff?
除了执行所有这些“同步(对象)等待(..)通知(..)”之外,是否有更好的等待响应消息的方法?
Best regards, bigbohne
最好的问候,bigbohne
Maybe to add some spice:
也许添加一些香料:
This should all end in a webinterface where user can request these commands (either through ajax or directly). I've also thought of caching responce values in a database. But for some commands you MUSS have a direct answer of success/failure
这应该都以用户可以请求这些命令的 web 界面结束(通过 ajax 或直接)。我还考虑过在数据库中缓存响应值。但是对于某些命令,您 MUSS 可以直接回答成功/失败
采纳答案by Robin
You can do this with a BlockingQueue so you will not have to manually manage any of the synchronization. The request can send the message, then call take() on a BlockingQueue which will wait for an element to be present. The element is the reply which is inserted into the queue by whatever listener you have on the port when the reply is returned.
您可以使用 BlockingQueue 执行此操作,因此您不必手动管理任何同步。请求可以发送消息,然后在 BlockingQueue 上调用 take() ,它将等待元素出现。元素是回复,当回复返回时,您在端口上的任何侦听器都会将回复插入到队列中。
You just have to coordinate so that the listener and requester share the same queue. You only need a queue of size one for each request to support this scenario.
您只需要协调,以便侦听器和请求者共享同一个队列。对于每个请求,您只需要一个大小为 1 的队列来支持这种情况。
// Send method
BlockingQueue<Reply> q = new ArrayBlockingQueue<Reply>(1);
serialCom.registerQueue(myRequest.getId());
serialCom.sendRequest(myRequest);
return q.take();
//Listener
BlockingQueue<Reply> q = queueMap.get(incomingMessage.getId());
q.add(incomingMessage.getReply());
回答by Henrik Gustafsson
I'm not sure I understand the question correcly, but I usually use a Future<T>
for these sorts of tasks.
我不确定我是否正确理解了这个问题,但我通常将 aFuture<T>
用于这些类型的任务。
Internally the Future<T>
implementation uses wait and notify and all of that, but the interface itself becomes rather clean.
在内部Future<T>
实现使用等待和通知以及所有这些,但接口本身变得相当干净。
Future<Double> getTemperature(int id);
In your communication code you then can map incoming messages towards unfulfilled futures. If ordering is guaranteed you could do something like
在您的通信代码中,您可以将传入的消息映射到未实现的未来。如果可以保证订购,您可以执行以下操作
class Something {
Map<Integer, Queue<Object>> 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.
}
}
Where MyFutureImpl is a very basic future-implementation. I'm assuming there's a communications thread that calls response()
when a packet is received. I'm also assuming that the serializeAndSend()
-function handles the writing to the client or blocks until the write operation can be made or handed off to a communication thread.
其中 MyFutureImpl 是一个非常基本的未来实现。我假设有一个通信线程response()
在收到数据包时调用。我还假设serializeAndSend()
-function 处理对客户端的写入或阻塞,直到可以进行写入操作或将其移交给通信线程。
The use of concurrency-capable map and queue structures could make some synchronization
s unnecessary. If there's only ever one outstanding call per id, the Queue becomes unnecessary of course.
使用具有并发能力的映射和队列结构可能会使某些synchronization
s变得不必要。如果每个 id 只有一个未完成的调用,那么队列当然就变得没有必要了。
回答by Erick Robertson
The better way is to wrap it up in some reusable request/response class. This way you can have a standard way to query the serial port and wait for a response. This class, however, will undoubtedly have to use the synchronized keyword and wait and notify commands somewhere in its implementation. This is a key part of writing Java and it's important to understand how they work.
更好的方法是将其包装在一些可重用的请求/响应类中。通过这种方式,您可以使用标准方法来查询串行端口并等待响应。然而,这个类无疑必须在其实现中的某处使用synchronized 关键字和wait 和notify 命令。这是编写 Java 的关键部分,了解它们的工作原理很重要。
If you were to design a function like you say, you have to make sure that you call it from a thread which can block waiting for the result. The function will have to implement some sort of a wait loop inside of it waiting for the response from the serial port. So it's important that whatever thread it's running on be able to wait as well.
如果你要像你说的那样设计一个函数,你必须确保你从一个可以阻塞等待结果的线程中调用它。该函数必须在其内部实现某种等待循环,以等待来自串行端口的响应。所以重要的是它运行的任何线程也能够等待。
This does bring up one additional point, too. If you have multiple threads doing this, you will need to have some class which handles the serial port communication that can deal with multiple requests coming in from multiple threads and queue them as necessary to handle the asynchronous nature of the serial port and the specific device to which you are connecting. For example, it may not be appropriate to send a second command before the response from the first is read completely.
这也带来了额外的一点。如果您有多个线程执行此操作,则需要有一些处理串行端口通信的类,该类可以处理来自多个线程的多个请求,并根据需要对它们进行排队以处理串行端口和特定设备的异步性质您正在连接的。例如,在完全读取第一个命令的响应之前发送第二个命令可能是不合适的。
There are several complicated issues here, and it's important to have a good design in place which addresses them all in a reasonable way.
这里有几个复杂的问题,重要的是要有一个好的设计,以合理的方式解决所有问题。