Open nuessgens opened 6 years ago
To simulate the Thread Scheduling madness one can add Thread.sleep()
or Thread.yield()
between shutting down the executor service and setting it to null:
BaseContainer
public void shutdown() {
if (executorService != null) {
executorService.shutdown();
for (int i = 0; i < 100; i++) {
Thread.yield();
}
executorService = null;
}
if (scheduledExecutorService != null) {
scheduledExecutorService.shutdownNow();
scheduledExecutorService = null;
}
}
Neither sleep nor yield do release the EXECUTORS_CLEAN_UP_LOCK
(acquired in shutdown(ShutDownCondition)
) but should simulate that the other thread was granted processing time and the current thread was put on hold.
Here is my test program (.txt
-> .java
):
TyrusRejectBug.txt
Furthermore due the RejectedExecutionException activeClientCounter
is not decremented / onConnectionTerminated
is never called. Therefore activeClientCounter remains > 0 forever and the auto-cleanup mechanism does not work anymore / exec will never be stopped
In rare cases the
ClientManager
(or ratherBaseContainer
) shuts down the executor-service although there are active clients (activeClientCounter != 0)In my test-scenario the application re-uses the ClientManger instance. The test tries to connect to a non existing server (which - of course - fails). As soon as the connect fails a new connect is made by calling
ClientManager.asyncConnectToServer()
again. There is no managed executor-service so the BaseContainer maintains it's own and tries to stop it if all sessions/clients where disconnected.In some situations I get an
RejectedExecutionException
when callingClientManager.asyncConnectToServer()
. I noticed huge differences regarding the frequency (/reproducibility) of this behavior between different machines (e.g. Windows 10 desktop pc Intel Core i7 80 2.9 GHz Oracle JDK 1.8.0_121 and windows 10 notebook Intel Core i7-7700HQ 2.8Ghz Oracle JDK 1.8.0_131. It is easier to reproduce on the notebook.I added some log-statements (async-logging) to the following classes.
BaseContainer
ClientManager
In the rare cases mentioned above the following output is made:
Here is the corresponding exception:
IMHO the construct (shutdown evaluation criteria and locking) is not consistent. After T1 evaluated the shutdown-criteria (
activeClientCounter.get()==0
) another thread T2 could callactiveClientCounter.incrementAndGet()
/onConnectionInitiated()
and get the executor-service by callinggetExecutorService()
. Because theexecutorService
is not yet null no lock is acquired and the terminating executor-service is returned. After that T1 awakes and shuts down the executor and sets it to null. After that T2 kicks in again and tries to submit the actual connect-task.