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: with no references left to the ServerSocket instance, what would free the socket for a new connection? At what point would the ServerSocket become garbage collected? In general, what are good practices I can follow to avoid this type of bug?