Edit:
To test this problem outside of Android environment I've created a Java application that creates an ExecutorService
, provides a task of AttackScript
(identical class) and then terminates.
This works 100% as expected, the thread is interrupted and the task is stopped.
You don't even have to cancel a task by its Future.cancel(true)
. ExecutorService.shutdownNow()
does the job. Is there something in the Android's Service
that somehow messes with the thread pool?
Code that works as expcepted:
public static void main(String[] args) {
AttackScript script = new AttackScript("http://ninjaflex.com/");
ExecutorService executor = Executors.newFixedThreadPool(5);
executor.submit(script);
executor.submit(script);
executor.submit(script);
executor.submit(script);
sleep(1300);
// Automatically interrupts threads in the pool.
executor.shutdownNow();
}
private static void sleep(long timeMilli){
try {
Thread.sleep(timeMilli);
} catch(Exception e) {
System.out.println("Error sleep()");
}
}
Original post:
I have an Android Service
where it includes an ExecutorService
field, responsible to run some tasks.
The tasks are objects of the AttackScript
class. I cache the Future
references in a Map<String,Future>
, called tasks, so that I will be able to cancel them later.
Future future = executor.submit(new AttackScript(attack.getWebsite()));
tasks.put(attack.getPushId(), future);
In Service
'sonDestroy()
(called when user presses a notification button) I am cancelling all tasks
private void cancelAllTasks() {
for (Map.Entry<String, Future> futureEntry : tasks.entrySet()) {
futureEntry.getValue().cancel(true);
}
}
and then shutdown the executor:
private void shutdownThreadPool() {
// https://www.baeldung.com/java-executor-service-tutorial
executor.shutdown();
try {
if (executor.awaitTermination(800, TimeUnit.MILLISECONDS))
executor.shutdownNow();
} catch (InterruptedException e) {
executor.shutdownNow();
}
}
Finally here is the AttackScript class:
public class AttackScript implements Runnable {
private static final String TAG = "AttackScript";
private URL url;
public AttackScript(String website) {
initializeUrl(website);
}
private void initializeUrl(String website) {
try {
url = new URL(website);
} catch (MalformedURLException e) {
Log.e(TAG, "Wrong url?", e);
}
}
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
readUrl();
}
Log.d(TAG, "Stopped requesting from " + url + " server.");
}
private void readUrl() {
InputStream in = null;
try {
in = url.openStream();
} catch (IOException e) {
Log.e(TAG, "openStream() error.", e);
} finally {
closeInputStream(in);
}
}
private void closeInputStream(InputStream in) {
try {
in.close();
Log.d(TAG, "InputStream closed for " + url);
} catch (IOException e) {
Log.e(TAG, "Error while closing the input stream.", e);
}
}
}
The weird part is that rarely, like 1 out of 10, tasks are interrupted and AttackScript
's execution stops. But the other 9 the tasks were not interrupted, continuing to openStreams() on URL
s.