Java RMI远程调用,客户端会创建TCP连接来跟服务器端会话。客户端需要创建并管理这些连接。连接的复用可以减少频繁的创建TCP连接,要实现并发的远程访问又需要创建多个连接。那么Java RMI是怎么管理TCP连接的呢?本文简单探索了JDK19中RMI连接管理的模型。
核心实现类 JDK默认使用UnicastRef来发起远程调用,每个UnicastRef对象对应一个客户端的代理对象。每个UnicastRef对象对应1个TCPChannel对象,TCPChannel内的TCPEndpoint就包含请求的IP+port。TCPChannel内部维护一个可复用的连接列表freeList。TCPChannel创建连接默认使用了TCPDirectSocketFactory,而TCPDirectSocketFactory每次都会创建新的连接。
连接池模型 阅读代码后可见JDK里的连接管理的模型其实较为简单:

  • 每个远程调用的对象都会维护自己的连接池,连接池里没有可用链接就创建新的连接。
  • 新的连接使用完后放入连接池freeList。
  • 每个连接默认如果空闲了15秒则被清理掉。
  • 默认没有对最大可创建的连接数做限制,所以任何一次远程调用都不会因为连接不够用而被阻塞。

单次远程调用的过程如图: image.png|200x100
并发问题

  • 每个连接被获取后只会被当前的线程使用,所以没有并发使用同一个连接的问题。
  • 可能同时有多个线程使用同一个对象发起远程调用,所以存在并发的从连接池(freeList)中获取连接的情况,因此JDK里对freeList的访问都加了synchronized锁。


可能的优化 以上可见RMI同样可以借鉴HTTP2的Multiplexing多路复用的思路进行优化。