开发者

What happens to an instance of ServerSocket blocked inside accept(), when I drop all references to it?

开发者 https://www.devze.com 2022-12-25 03:51 出处:网络
In a multithreaded Java application, I just tracked down a strange-looking bug, realizing that what seemed to be happening was this:

In a multithreaded Java application, I just tracked down a strange-looking bug, realizing that what seemed to be happening was this:

  • one of my objects was storing a reference to an instance of ServerSocket
  • on startup, one thread would, in its main loop in run(), call accept() on the socket
  • while the socket was still waiting for a connection, another thread would try to restart the component
  • under some conditions, the restart process missed the cleanup sequence before it reached the initialization sequence
  • as a result, the reference to the socket was overwritten with a new instance, which then wasn't able to bind() anymore
  • the socket which was blocking inside the accept() wasn't accessible anymore, leaving a complete shutdown and restart of the application as the only way to get rid of it.

Which leaves me wondering: a) Does the blocking call prevent, or interfere with, GC in any way? b) If the ServerSocket does get GCed, will that make the socket available again?

In general, what are good practices I can follow to avoid this type of bug? 开发者_开发问答For instance, I learned two lessons here:

  • All lifecycle logic (i. e. component level, init-start-stop-cleanup cycles) must be synchronized. Rather obvious, I guess, but I didn't take it seriously enough.
  • Lifecycle logic should be as simple as possible to avoid my problem of non-obvious code paths that skip cleanup or initialization steps.


You should always close() ServerSocket if you want a predictable cleanup.

The fact that all the references have been dropped only means that it is available for GC, not that it ever will be GC'ed. With available process memory in megabytes, there is a very small chance that a single object will be garbage collected in short period.

Usually you call close from a maintenance thread. In many server apps it would be called from the shutdown hook.


To answer the question in the title: nothing will happen to the ServerSocket. There's still a reference to your ServerSocket from the call stack of the thread blocking on the accept() call; this reference will keep the ServerSocket from being eligible for garbage colelction.


Since you brought up the topic of life cycle methods, let me share something I had done when I wanted to create adapters for different socket oriented protocols.

I made a generic component called SocketServer which listens on a port and accepts connections. Once a connection is established, it passes the Socket object to a class implementing SocketHandler in a separate thread.

SocketHandler has methods like onSocket(Socket socket); init(); destroy();

SocketServer has methods like startServer(); stopServer();

The socket server's properties such as port and SocketHandler instance can be easily configured using Spring.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号