Wednesday, June 3, 2020

HttpClient Daemon Threads

I have discovered that java.net.http.HttpClient.send leaves daemon threads that do not terminate when interrupted.

I am using
  • Maven 1.6
  • Java 1.14
  • NetBeans 11.3
When I make a simple HTTP request using HttpClient.send using the maven goal exec.java, the code runs, but pauses and I get these warnings after 15 seconds, and then the app stops:

thread Thread[HttpClient-1-Worker-0,5,org.sonatype.mavenbook.ch07.simple.weather.oauth.lone.WeatherYdnJava] was interrupted but is still alive after waiting at least 14997msecs
thread Thread[HttpClient-1-Worker-0,5,org.sonatype.mavenbook.ch07.simple.weather.oauth.lone.WeatherYdnJava] will linger despite being asked to die via interruption
thread Thread[HttpClient-1-Worker-1,5,org.sonatype.mavenbook.ch07.simple.weather.oauth.lone.WeatherYdnJava] will linger despite being asked to die via interruption
thread Thread[HttpClient-1-Worker-2,5,org.sonatype.mavenbook.ch07.simple.weather.oauth.lone.WeatherYdnJava] will linger despite being asked to die via interruption
NOTE: 3 thread(s) did not finish despite being asked to  via interruption. This is not a problem with exec:java, it is a problem with the running code. Although not serious, it should be remedied.
Couldn't destroy threadgroup org.codehaus.mojo.exec.ExecJavaMojo$IsolatedThreadGroup[name=org.sonatype.mavenbook.ch07.simple.weather.oauth.lone.WeatherYdnJava,maxpri=10]


It is interesting that if I use the Play button in NetBeans to run the code, it works without any warnings. NetBeans uses exec:exec instead of exec:java. One difference between exec:java and exec:exec is how daemon threads are handled. With exec:java, after maven is done doing its work, maven sends an interrupt to all the daemon threads, hoping that they will terminate nicely. The exec:java goal also runs the code in the same VM as maven.

The exec:exec goal does not show the warning. I do not know the reason, but it could be that it terminates the threads unceremoniously or it waits for them to finish.

Some properties for the exec:java goal control how daemon threads are handled.
  • daemonThreadJoinTimeout - if I set this to 60 seconds or more, then the daemon threads terminate on there own. I assume that the TCP connection was closed by one side, so the threads terminate.
  • cleanupDaemonThreads - if this is set to false, then the threads are not interrupted and the timeout is not used. I assume that the threads are killed.
  • stopUnresponsiveDaemonThreads - this is a bad idea for this example. If I set this to true, the app will never end. As soon as one is killed, another pops up in its place. I assume this would continue for a minute in this case, waiting for the TCP connection to close.
Conclusion: I will use exec:exec. The downside of using exec:exec is that it creates a separate VM to run the java program. If that becomes a problem, I will set cleanUpDaemonThreads to false in the exec:java goal.

No comments:

Post a Comment

Followers