代码之家  ›  专栏  ›  技术社区  ›  Bigbohne

同步异步任务的最佳方法

  •  12
  • Bigbohne  · 技术社区  · 15 年前

    我可以将包发送到网络并侦听传入的包。 可以想象,这是高度异步的。

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

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

    除了做这些“synchonized(object)wait(..)notify(..)”之类的事情之外,还有更好的等待响应消息的方法吗?

    顺致敬意, 比博恩

    这一切都应该在一个webinterface中结束,用户可以在其中请求这些命令(通过ajax或直接)。我还考虑过在数据库中缓存responce值。 但对于某些命令,你必须有一个成功/失败的直接答案

    3 回复  |  直到 15 年前
        1
  •  7
  •   Robin    15 年前

    您可以使用BlockingQueue来实现这一点,这样就不必手动管理任何同步。请求可以发送消息,然后调用BlockingQueue上的take(),它将等待元素出现。元素是在返回应答时由端口上的任何侦听器插入队列的应答。

    您只需进行协调,以便侦听器和请求者共享同一个队列。每个请求只需要一个大小为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());
    
        2
  •  2
  •   Henrik Gustafsson    15 年前

    Future<T>

    内部 未来<T> 实现使用wait和notify以及所有这些,但是接口本身变得相当干净。

    Future<Double> getTemperature(int id);
    

    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.
        }
    }
    

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

    使用具有并发能力的映射和队列结构可以 synchronization 没必要。如果每个id只有一个未完成的调用,那么队列当然就没有必要了。

        3
  •  1
  •   Erick Robertson    15 年前

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

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

    这也带来了另外一点。如果有多个线程执行此操作,则需要有一个处理串行端口通信的类,该类可以处理来自多个线程的多个请求,并根据需要对它们进行排队,以处理串行端口和所连接的特定设备的异步性。例如,在第一个命令的响应被完全读取之前发送第二个命令可能是不合适的。

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

    推荐文章