Java 多线程套接字通信中的场景

Java 多线程套接字通信中的场景,java,multithreading,sockets,Java,Multithreading,Sockets,我有一个socket客户端应用程序,在应用程序启动期间,会创建socket(与服务器建立连接),并启动两个并行运行的线程 线程1:使用读取方法连续读取套接字(块直到接收到数据) 线程2:连续写入数据 在写入套接字时,如果线程2接收到IO异常,那么它将丢弃现有套接字并创建新套接字并开始通信。由于线程2丢弃套接字,因此线程1接收空指针异常。 我们是否有任何策略来处理此问题您开始遇到与系统设计的proactor风格相关的问题。解决此问题需要两个线程之间进行一些通信。选择什么样的沟通方式会让事情变得一团

我有一个socket客户端应用程序,在应用程序启动期间,会创建socket(与服务器建立连接),并启动两个并行运行的线程

线程1:使用读取方法连续读取套接字(块直到接收到数据)

线程2:连续写入数据

在写入套接字时,如果线程2接收到IO异常,那么它将丢弃现有套接字并创建新套接字并开始通信。由于线程2丢弃套接字,因此线程1接收空指针异常。
我们是否有任何策略来处理此问题

您开始遇到与系统设计的
proactor
风格相关的问题。解决此问题需要两个线程之间进行一些通信。选择什么样的沟通方式会让事情变得一团糟。它必须能够阻止thread1尝试读取套接字。我不太擅长Java,但在C中,这意味着使用信号

我建议您避免使用信号,即使Java中也有类似的信号

一个更好的选择是在调用
select()
(或其他Java等价物)时阻塞thread1,等待套接字和管道。Thread2在希望关闭套接字时写入管道,thread1从select()返回,沿管道向下写入对Thread2的响应,并再次调用select(),但仅在管道上调用。Thread2读取该响应,关闭套接字,打开一个新的套接字,沿管道发送其他内容以再次唤醒thread1,thread1现在可以返回到
select()
,但这次是在管道和新套接字上。这实现了thread1和thread2之间的执行会合;thread2可以关闭旧插座并打开新插座,因为它知道(通过管道通信)thread1何时不使用插座

这有点乱。而且越来越像
反应堆
设计模式。在这种情况下,也可以只使用一个线程,使用
select()
来选择是否将套接字作为它正在执行的任何循环的一部分来读取。这个单线程将在数据可用时读取数据,而不是希望数据到达而进行阻塞读取。如果套接字写入出现问题,需要更换套接字,那么它只需更换套接字即可;没有其他线程可以同步。假设您的套接字连接到网络上的远程服务器(而不是同一台机器上的服务),以太网的速度仍然是主要的瓶颈;反应堆式系统并不慢

一般来说,使用
reactor
系统样式处理网络故障要容易得多,因为没有线程承诺执行其他线程知道不合适的操作。不幸的是,大多数编程环境都是
proactor
,例如Windows、Boost ASIO、RabbitMQ等。在出现问题之前,proactor系统是正常的,在这之后,通常有必要扔掉整个过程,因为对于程序员来说,整理所有错误的回调和异步IOs很容易变得异常复杂


一种选择是如果可以,使用ZeroMQ。这要求您在任何地方都使用ZeroMQ(也使用服务器),但它使处理网络问题更加容易。这是一个反应器,不是一个促发剂

线程2需要关闭套接字以进行输入,然后再关闭它。这将导致线程接收并结束流,这将导致它关闭套接字并退出。然后线程2可以创建另一个套接字并启动另一个读取线程。

这不是“异步”,而是多线程。不一样。