In my application I have a wrapper over some native code, which is called via JNI bridge. This native code needs to be executed in separate thread (parallel processing). However the problem is that the code sometimes "hangs" so the thread needs to be terminated "by force". Unfortunately I haven't found any "delicate" method to do so: general advise is to tell the code in a thread to exit gracefully, but I can't do it with this native code (which is 3rd party code all above).
I use Java Concurrent API for task submission:
Future<Integer> processFuture = taskExecutor.submit(callable);
try {
result = processFuture.get(this.executionTimeout, TimeUnit.SECONDS).intValue();
}
catch (TimeoutException e) {
// How to kill the thread here?
throw new ExecutionTimeoutException("Execution timed out (max " + this.executionTimeout / 60 + "min)");
}
catch (...) {
... exception handling for other cases
}
Future#cancel()
will only interrupt the thread, but it will not terminate it. So I used the following trick:
class DestroyableCallable implements Callable<Integer> {
private Thread workerThread;
@Override
public Integer call() {
workerThread = Thread.currentThread();
return Integer.valueOf(JniBridge.process(...));
}
public void stopWorkerThread() {
if (workerThread != null) {
workerThread.stop();
}
}
}
DestroyableCallable callable = new DestroyableCallable();
Future<Integer> processFuture = taskExecutor.submit(callable);
try {
result = processFuture.get(this.executionTimeout, TimeUnit.SECONDS).intValue();
}
catch (TimeoutException e) {
processFuture.cancel(true);
// Dirty:
callable.stopWorkerThread();
ThreadPoolTaskExecutor threadPoolTaskExecutor = (ThreadPoolTaskExecutor) taskExecutor;
logger.debug("poolSize: " + threadPoolTaskExecutor.getPoolSize() + ", maxPoolSize:"
+ threadPoolTaskExecutor.getMaxPoolSize() + ", activeCount:"
+ threadPoolTaskExecutor.getActiveCount());
}
throw new ...;
}
catch (...) {
... exception handling for other cases
}
The questions/problems with this code:
- Is it in general the right way to do so? Any other more elegant alternatives?
activeCount
on task executor is not decreased, so task executor still "thinks" that thread is running- I had to add
workerThread != null
check tostopWorkerThread()
method, as this variable turned out to benull
on some case. I can't understand what are these cases...
Notes:
- Native code does not consume file descriptors (sockets). Everything is passed to it as block of data and returned the same way.
- Native code is CPU-intensive. Even though it guarantees to terminate, it may take a long time.
Bounty edit: The approach/suggestion to revisit the native code is clear, please do not offer it in your reply. I need pure-Java solution / workaround.