Saturday, 2 February 2019

Can't interrupt tasks of ExecutorService

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 URLs.



from Can't interrupt tasks of ExecutorService

No comments:

Post a Comment