5

我有2节课。一个 (A) 收集一些数据,另一个 (B) 将数据发送到 TCP/IP 客户端。该过程是异步的,刷新率几乎为零到几秒。请注意,此应用程序没有 GUI,因此我将无法使用许多内置的“onChange”侦听器。

在正常情况下,我会简单地编写代码,以便 A 在 B 上调用“发送”方法,传递数据,这里没有问题。

现在,假设 A 收集数据的速率至关重要(实时),并且 A 不能等待 B 完成发送过程(注意 B 使用 TCP,而不是 UDP)。我实现这个的方式是

  • A 将数据放在 B 的字段中
  • B 有一个连续循环来检查数据是新的还是现在的。如果是新的,它将发送出去。

如果在发送期间数据被更新了几次没关系,只要它不会减慢 A。为每次发送生成一个新线程原则上不会减慢 A,但它可能会导致一团糟.

您可以看到 B 在同步模式下工作(但 A 不是),它是通过带有 Thread.sleep() 调用的 while 循环实现的。我的问题是:

  1. 我应该使用计时器任务而不是 while 循环吗?我知道大多数人讨厌 Thread.sleep() 调用,但最终我唯一感兴趣的是保持 CPU 较低。

  2. 难道没有比同步方法更优雅的方法吗?在某些情况下,A 的数据刷新大约需要 1 秒,如果我可以有一个对事件采取行动的侦听器,那就太好了。在这种情况下,25 毫秒的睡眠时间将浪费周期。在其他情况下,它非常快,我根本不想睡觉。

*示例:假设 A 正在从您的屏幕提交屏幕截图,而 B 正在将它们发送给客户端。只有最后一个很重要,B会尽可能快*

有什么想法或建议吗?请让事情尽可能简单和低cpu

多谢!

4

4 回答 4

2

当队列已满时,我会设置一个LinkedBlockingQueuebetween AB其大小不应阻塞。AA中,收集数据的方法会将其发布到队列中。在B中,只要队列中有一个项目,它就是新的,应该被发送出去。

如果您想B利用对消息的多次编辑来A合并并作为单个更新发送,那么我会使用Observer.

  1. A不断更新的消息是Observable.
  2. B是此消息的观察者。
  3. 每次A更新消息,都表明 B 采取一些行动。
  4. B可以选择立即将更新发送给客户端
  5. B也可以选择使用定时器等待一段时间,并在定时器触发后才将更新发送给客户端。发送更新的代码将是 TimerTask。
  6. BA在更改消息之前不会再次设置计时器。
于 2012-09-16T14:21:24.530 回答
2

我会这样:

A 以任何合适的方式收集数据,然后发布“下一条消息”以发送。如果已经有消息待处理,让新消息替换/更新以前的消息。

B 检查任何待处理的消息,如果可用,它会抓取它并将其发送给客户端。但是,如果没有消息未决,则 B 等待有一个消息可用。

Object lock = new Object();
Object pending = null;

public void post(Object message) {
    synchronized (lock) {
        pending = message;
        lock.notifyAll();
    }
}

public Object getNextMessage() {
    Object message;
    synchronized (lock) {
        while (pending == null) {
            try {
                lock.wait();
            } catch (InterruptedException e) {
                // Ignore
            }
        }
        message = pending;
        pending = null;
    }
    return message;
}

使用队列你可以做

BlockingDeque<Object> queue = new LinkedBlockingDeque<Object>(1);

public void postMessage(Object message) {
    // If previous message is still pending we replace it.
    queue.clear();
    queue.offer(message);
}

public Object getNextMessage() {
    while (true) {
        try {
            return queue.take();
        } catch (InterruptedException e) {
            // Ignore interrupts
        }
    }
}

当然,在这两个示例中,最好不要使用while (true)信号,这样您就可以优雅地关闭。

于 2012-09-16T14:35:46.343 回答
2

您可以使用交换器

B将发送信息,使用交换器进行交换(他可能会等待A和它的罚款)
一旦进行交换,他将发送信息。

A 将使用超时 0 的交换器,这意味着如果 B 尚未等待,那么我们跳过此交换,如果他等待交换将进行,A 将继续他的工作,B 现在可以发送信息。

B 忙时出现的信息将被忽略(如果 B 忙,A 中超时 0 的交换只会抛出异常,确保你抓住它)

于 2012-09-16T14:47:06.907 回答
1

最优雅的方式是使用消息队列A一旦数据可用,就将数据写入队列。B 订阅队列并在有新数据时收到通知。消息队列为您处理一切。

但是,您应该更明确:是否应该B收到每条消息的通知?如果更新丢失怎么办?

于 2012-09-16T14:20:58.597 回答