如何实现异步计算?

时间:2014-03-05 15:36:06

标签: java multithreading asynchronous

我一直在考虑在Java中实现异步处理的不同方法。我想到了一些可能性,想要了解一些是否比其他更好,并且可能会就如何做到这一点得到进一步的建议。最常见的用例是使用以下API void sendData(Data data)甚至void sendData(Data data, Handler handler)通过连接(例如TCP)发送数据包。以下是我的一些想法:

  1. 专用数据发送循环 - 有一个详细的线程,其行为有点像Java中的事件调度线程,所有其他线程调用并提交请求。这些请求存储在队列中,并定期排空队列并发送所有请求。
  2. 使用后台线程来排空队列 - Connection可以维护待处理请求列表,并有一个后台线程来排空队列(通过一些同步)
  3. 执行者服务 - 将请求传递给服务并从后台线程调用处理程序。
  4. 异步通道 - 最高级别的方法,委托给实现
  5. 是否有更好的使用方法,或者如果您有任何其他一般性想法,请分享您的意见。

3 个答案:

答案 0 :(得分:1)

你的大部分建议实际上是不同的方式来打扮同样的东西。

在幕后,执行程序服务具有一个或多个后台线程池,用于排队。请求将提交给它。

1和2都是说“排队要做的事情,有一个处理它的线程”的方式

所以基本上1和2都是彼此的变体。它们也是3的子集。

对于4.我不确定你的意思在这里?

ExecutorService旨在完成你想要做的事情 - 如果你有多个线程来执行任务,那么显然就是这样做的。

如果你只有一个线程,你仍然可以使用ExecutorService,但选择不太明确。使用一个线程和一个BlockingQueue是相当简单的,这样可能就是这样。

答案 1 :(得分:0)

我总是会使用执行程序服务来进行并发。它们的高级别足以隐藏管理线程的复杂性并允许线程重用。您可以将任务提交给执行程序,该执行程序将有效地充当队列,或者运行许多使用同步队列(如阻塞队列)来共享数据的任务。后者可能允许更多的灵活性,例如,对队列项进行批处理。

我还强烈推荐Guava ListenableFuture,因为它可以解决您在使用并发时可能遇到的许多问题。

答案 2 :(得分:0)

您应该将异步管道设计为具有数据/事件依赖关系的图形。典型图由两种节点组成:

fast handler:
     immediately invoked when an event happens and:
     probably stores the event,
     and/or calls another fast handler,
     and/or submits an asynchronous task to an executor

task:
     runs and issues events (that is, calls fast handlers)

所以基本上你需要开发两个独立的层:快速处理程序和任务执行程序。执行程序是通用的,可以从java.util.concurrent包中获取。快速处理程序在很大程度上取决于您的问题域,并且没有针对所有情况的通用库。例如,纯队列是一个只存储事件的快速处理程序,因此几乎没用。

如果使用I / O,则需要使用标准I / O库,以便为处理程序发出I / O事件。它可以使用线程进行同步I / O,也可以使用Selector线程或异步I / O的异步通道进行构建。

与NIO2异步通道一起使用的快速处理程序示例:

 class ConnectionAcceptor  implements CompletionHandler<AsynchronousSocketChannel, Void>{
   AsynchronousServerSocketChannel assc;
   int maxConn;// max number of simultaneous connections
   int connCount=0;

   /* called on creation to start listening incoming client connection requests */
   void allowAccept() {
       assc.accept(null, this);
   }

   /* called by I/O layer when a client connection requested */
   public synchronized void completed(AsynchronousSocketChannel result, Void attachment) {
      executor.exec(new Connection(result));
      connCount++;
      if (connCount<maxConn) {
        allowAccept();
      }
   }

   /* called by Connection when it is closed */
   synchronized void connClosed() {
      if (connCount==maxConn) {
        allowAccept();
      }
      connCount--;
   }
}

此处理程序有3个入口点并处理3种事件。类似地,可以创建用于进行读取或写入(但不是两者)的处理程序。而不是connCount,它的内部状态包含一个布尔标志,指示正在进行I / O操作,以及一个等待AsynchronousSocketChannel结束开始操作的缓冲区队列。