DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Last call! Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • How To Build Web Service Using Spring Boot 2.x
  • Multi-Threaded Geo Web Crawler In Java
  • Stretching Async/Await With Lambdas
  • Mastering Concurrency: An In-Depth Guide to Java's ExecutorService

Trending

  • Is Agile Right for Every Project? When To Use It and When To Avoid It
  • Automatic Code Transformation With OpenRewrite
  • Automating Data Pipelines: Generating PySpark and SQL Jobs With LLMs in Cloudera
  • The Human Side of Logs: What Unstructured Data Is Trying to Tell You
  1. DZone
  2. Culture and Methodologies
  3. Agile
  4. Understanding Thread Interruption in Java

Understanding Thread Interruption in Java

How to get a task running on a separate thread to finish early, or make that task responsive to such a finish request.

By 
Praveer Gupta user avatar
Praveer Gupta
·
Dec. 12, 15 · Tutorial
Likes (12)
Comment
Save
Tweet
Share
96.4K Views

Join the DZone community and get the full member experience.

Join For Free

You may come across use cases where you would need to perform some long running tasks on separate threads. You may have to request these tasks to finish doing their work, maybe even before the tasks are completely done, so that the threads they would be running on can be stopped. A few situations in which you may have to finish tasks early and stop threads are:

  • While servicing a web request you may distribute the processing to multiple threads and some or all of the tasks fail to finish the processing within specified request processing time, or
  • While shutting down an application that may use more than one thread to do some work, which may not have completed.

In this article I will try to answer the following questions:

  • How to request a task, running on a separate thread, to finish early?
  • How to make a task responsive to such a finish request?

Let’s try to answer the two questions by implementing an use case.

Example Use Case

The following are the requirements of the use case:

  1. Make a task that prints 0 through 9 on console.
  2. After printing a number the task should wait 1 sec before printing the next number.
  3. The task runs on a separate thread, other than main application thread.
  4. After starting the task the main application should wait for 3 sec and then shutdown.
  5. On shutdown the application should request the running task to finish.
  6. Before shutting down completely the application should, at the max, wait for 1 sec for the task to finish.
  7. The task should respond to the finish request by stopping immediately.

As per the requirements mentioned in the use case the task will take minimum 9 seconds to complete. Therefore after 3 seconds the main application will have to request the task to finish and if implemented correctly the task will not be able to print all the ten numbers from 0 through 9.

In this article, I will be focusing on the implementations of requirement 5 and requirement 7.

An Implementation of the Use Case Using Thread

The inline comment against a line of code mentions the use case requirement that has been met by the line.

public static void main(String[] args) throws InterruptedException {
    Thread taskThread = new Thread(taskThatFinishesEarlyOnInterruption());
    taskThread.start();      // requirement 3
    Thread.sleep(3_000);     // requirement 4
    taskThread.interrupt();  // requirement 5
    taskThread.join(1_000);  // requirement 6
}

private static Runnable taskThatFinishesEarlyOnInterruption() {
    return () -> {
        for (int i = 0; i < 10; i++) {
            System.out.print(i);      // requirement 1
            try {
                Thread.sleep(1_000);  // requirement 2
            } catch (InterruptedException e) {
                break;                // requirement 7
            }
        }
    };
}


Understanding the Implementation of Requirement 5

In the implementation of requirement 5, the main thread calls the taskThread’s interrupt() method. In Java, one thread cannot stop the other thread. A thread can only request the other thread to stop. The request is made in the form of an interruption. Calling the interrupt() method on an instance of aThread sets the interrupt status state as true on the instance.

Use interruption to request a task, running on a separate thread, to finish.

Understanding the Implementation of Requirement 7

In the implementation of requirement 7, InterruptedException is being handled by breaking out of the loop and thus finishing the task early.

Question arises that why did Thread.sleep() throw an InterruptedException? As soon as the taskThread was interrupted by the main thread, the Thread.sleep(1_000) responded to the interruption by throwing the exception. In fact almost all blocking methods respond to interruption by throwing InterruptedException.The decision of what to do in the case of interruption is left to the implementing code, which in this example is breaking out of the for loop as per the requirement in the use case.

Note: Calls to sleep() and join() methods in main() method are blocking and may also throw InterruptedException upon interruption. Handling of the exception here has been omitted for brevity.

Handle interruption request, which in most cases is done by handling InterruptedException, in the task to make it responsive to a finish request.

An Implementation of the Use Case Using the Executor

The same use case can be implemented using Executor framework provided by Java and can be found under the java.util.concurrent package. Usage of the Executor framework is preferred over Threads as it provides separation of task execution from the thread management. In the implementation below the task is submitted to ExecutorService, a sub-interface of Executor, using the submit() method. The service runs the task on the thread it holds. The service’s shutdownNow() method interrupts the currently running task andawaitTermination() method waits for the service to shutdown.

public static void main(String[] args) throws InterruptedException {
    ExecutorService executor = Executors.newSingleThreadExecutor();
    executor.submit(taskThatFinishesEarlyOnInterruption());  // requirement 3
    Thread.sleep(3_000);                                     // requirement 4
    executor.shutdownNow();                                  // requirement 5
    executor.awaitTermination(1, TimeUnit.SECONDS);          // requirement 6
}

// implementation of taskThatFinishesEarlyOnInterruption() remains the same

When using the Executor framework, you can interrupt a specific task without shutting down theExecutorService. On submitting a task to the service an instance of Future<?> is returned by the service. You may call the cancel() method on that instance to interrupt the task. In situations when you service a web request by running parallel tasks, this method of cancelling tasks and not shutting down the service helps in re-using the service across multiple requests. In such situations you may want to shutdown the service only on shutdown of your web application. Calling the cancel() with true causes the task to be interrupted.

Future<?> submittedTask = executor.submit(someTask());
...
submittedTask.cancel(true) // if conditions to cancel the task have been met

The Executor framework is a complete asynchronous task execution framework. If you have not explored it yet, I request to you to read about it. It will be a great addition to your development toolbox.

InterruptedException and Interruption Status

Before I finish, I wanted to emphasize on an important detail about what happens to a thread’s interruption status when a blocking code responds to interruption by throwing InterruptedException. I had left out the detail till now to avoid confusion.

Before a blocking code throws an InterruptedException, it marks the interruption status as false. Thus, when handling of the InterruptedException is done, you should also preserve the interruption status by callingThread.currentThread().interrupt().

Let’s see how this information applies to the example below. In the task that is submitted to the ExecutorService, the printNumbers() method is called twice. When the task is interrupted by a call toshutdownNow(), the first call to the method finishes early and then the execution reaches the second call. The interruption is called by the main thread only once. The interruption is communicated to the second execution of the printNumber() method by the call to Thread.currentThread().interrupt() during the first execution. Hence the second execution also finishes early just after printing the first number. Not preserving the interruption status would have caused the second execution of the method to run fully for 9 seconds.

public static void main(String[] args) throws InterruptedException {
    ExecutorService executor = Executors.newSingleThreadExecutor();
    Future<?> future = executor.submit(() -> {
        printNumbers(); // first call
        printNumbers(); // second call
    });
    Thread.sleep(3_000);                                     
    executor.shutdownNow();  // will interrupt the task
    executor.awaitTermination(3, TimeUnit.SECONDS);
}

private static void printNumbers() {
    for (int i = 0; i < 10; i++) {
        System.out.print(i);
        try {
            Thread.sleep(1_000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt(); // preserve interruption status
            break;
        }
    }
}

Summary

The answers to the two questions that I had set out to answer are:

  • How to request a task, running on a separate thread, to finish early? - Use interruption.
    • If using Thread directly in your code, you may call interrupt() on the instance of thread.
    • If using Executor framework, you may cancel each task by calling cancel() on Future
    • If using Executor framework, you may shutdown the ExecutorService by calling theshutdownNow() method.
  • How to make a task responsive to such a finish request? - Handle interruption request, which in most of the cases is done by handling InterruptedException. Also preserve the interruption status by calling Thread.currentThread().interrupt().
Task (computing) Requests Use case Java (programming language) application Web Service Requirement Implementation

Published at DZone with permission of Praveer Gupta. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • How To Build Web Service Using Spring Boot 2.x
  • Multi-Threaded Geo Web Crawler In Java
  • Stretching Async/Await With Lambdas
  • Mastering Concurrency: An In-Depth Guide to Java's ExecutorService

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!