检查ObjectInputStream是否有任何内容可以不阻塞地读取?

时间:2013-11-01 12:28:15

标签: java multithreading sockets client-server inputstream

我在java中构建一个同时与多个客户端通信的服务器,我们的初始方法是服务器监听来自客户端的连接,一旦收到连接并创建套接字,新线程生成以处理与每个客户端的通信,即使用ObjectInputStream读取请求,执行所需操作(从数据库获取数据,更新数据等),并将响应发送回客户端(如果需要)。虽然服务器本身回去听更多的连接。

这暂时工作正常,但是这种方法并不是真正可扩展的,它适用于同时连接的少量客户端,但是由于每个客户端产生另一个线程,当有一个也会发生什么许多客户一次连接?

所以我的下一个想法是维护一个包含所有连接客户端(套接字对象和一些额外信息)的排序列表,使用ThreadPool迭代它们并读取它们发送的任何内容,如果收到消息则把它放在一个队列中,由另一个工作线程的ThreadPool执行,一旦工人完成了它的任务,如果需要响应,则发送它。

后两个步骤实现起来非常简单,问题是每个客户端实现的原始线程,我使用ObjectInputStream.readObject()来读取消息,这个方法阻塞,直到有东西要读,这是对于这种方法很好,但我不能对新方法使用相同的东西,因为如果我阻塞每个套接字,我将永远不会到达列表中的那些。

所以我需要一种方法来检查在调用readObject()之前是否有任何要阅读的内容,到目前为止我尝试了以下解决方案:

解决方案1: 使用ObjectInputStream.available()检查是否有可读的内容,此方法失败,因为此方法似乎总是返回0,无论流中是否有对象。所以这根本没有用。

解决方案2: 使用PushbackInputStream检查流中是否存在第一个未读字节,如果存在,则将其推回并使用ObjectInputStream读取对象,如果它不继续:

            boolean available;
            int b = pushbackinput.read();
            if (b==-1)
                  available = false;
            else
            {
                pushbackinput.unread(b);
                available = true;
            }
            if (available)
            {
            Object message= objectinput.readObject();
            // continue with what you need to do with that object
            }

事实证明这也没用,因为如果没有要读取的输入,read()也会阻塞。如果流关闭,它似乎只返回-1选项。如果流仍然打开但是空它只是阻塞,所以这与简单地使用ObjectInputStream.readObject();

没有什么不同

任何人都可以提出一种实际可行的方法吗?

1 个答案:

答案 0 :(得分:1)

这是一个很好的问题,你已经完成了一些功课......但它涉及到历史记录以确保正确。注意,您的问题实际上更多地与套接字级通信而不是ObjectInputStream:

有关

过去最简单的方法是每个插槽有一个单独的线程。这可以扩展到一定程度,但线程昂贵且创建缓慢。

作为回应,对于大型系统,人们创建线程池,并在有工作要做时为线程上的套接字提供服务。这很复杂。

然后使用java.nio包更改了Java语言,该包引入了Selector和非阻塞IO。这创建了一种可靠(尽管有时令人困惑)的方式来为多个线程服务多个套接字。在你的情况下,它不会完全/很多,因为你想知道什么时候准备好读取一个完整的对象,而不是只有'某些'对象。

在此期间,“格局”发生了变化,Java现在能够更有效地创建和管理线程。 “当前”的想法是,每个套接字再次分配单个线程更好/更快更容易....参见Java thread per connection model vs NIO

在你的情况下,我建议你坚持使用每插槽线程模型,你会没事的。

,Java可以扩展和处理比套接字更多的线程,所以你会没事的。