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

  • Open Source: A Pathway To Personal and Professional Growth
  • Enhancing Software Quality with Checkstyle and PMD: A Practical Guide
  • Linting Excellence: How Black, isort, and Ruff Elevate Python Code Quality
  • Mastering GitHub Copilot: Top 25 Metrics Redefining Developer Productivity

Trending

  • A Complete Guide to Modern AI Developer Tools
  • Start Coding With Google Cloud Workstations
  • Is Agile Right for Every Project? When To Use It and When To Avoid It
  • Automatic Code Transformation With OpenRewrite

Why Do We Need Thread.currentThread().interrupt() in Interruptible Methods?

Let's evaluate why we need Thread.currentThread().interrupt() in interruptible methods.

By 
Anghel Leonard user avatar
Anghel Leonard
DZone Core CORE ·
Updated Nov. 05, 19 · Presentation
Likes (8)
Comment
Save
Tweet
Share
71.7K Views

Join the DZone community and get the full member experience.

Join For Free

Why Do We Need Thread.currentThread().interrupt() in Interruptible Methods?

Why Do We Need Thread.currentThread().interrupt() in Interruptible Methods?

By an interruptible method, we mean a blocking method that may throwInterruptedException, for example, Thread.sleep(),  BlockingQueue.take(),  BlockingQueue.poll(long timeout, TimeUnit unit), and so on. A blocking thread is usually in a BLOCKED, WAITING, or TIMED_WAITING state, and if it is interrupted, then the method tries to throw InterruptedException as soon as possible.

Since InterruptedException is a checked exception, we must catch it and/or throw it. In other words, if our method calls a method that throws InterruptedException, then we must be prepared to deal with this exception. If we can throw it (propagate the exception to the caller), then it is not our job anymore. The caller has to deal with it further. So, let's focus on the case when we must catch it. Such a case can occur when our code is run inside Runnable, which cannot throw an exception.

You may also like: Java Thread Tutorial: Creating Threads and Multithreading in Java

Let's start with a simple example. Trying to get an element from BlockingQueue via
 poll(long timeout, TimeUnit unit)can be written as follows:

try {
   queue.poll(3000, TimeUnit.MILLISECONDS);
} catch (InterruptedException ex) {
   ...
   logger.info(() -> "Thread is interrupted? "
      + Thread.currentThread().isInterrupted());
}


Attempting to poll an element from the queue can result in an InterruptedException. There is a window of 3,000 milliseconds in which the thread can be interrupted. In case of interruption (for example,  Thread.interrupt() ), we may be tempted to think that calling Thread.currentThread().isInterrupted()   in the catch block will return true.

After all, we are in an InterruptedException  catch block, so it makes sense to believe this. Actually, it will return false, and the answer is in the source code of the poll(long timeout, TimeUnit unit) method listed as follows:

1: public E poll(long timeout, TimeUnit unit)
         throws InterruptedException {
2: E e = xfer(null, false, TIMED, unit.toNanos(timeout));
3: if (e != null || !Thread.interrupted())
4:    return e;
5: throw new InterruptedException();
6: }


More precisely, the answer is in line 3. If the thread was interrupted, then  Thread.interrupted() will return true and will lead to line 5 ( throw new InterruptedException() ). But beside testing, if the current thread was interrupted, Thread.interrupted() clears the interrupted status of the thread. Check out the following succession of calls for an interrupted thread:

Thread.currentThread().isInterrupted(); // true
Thread.interrupted() // true
Thread.currentThread().isInterrupted(); // false
Thread.interrupted() // false


Notice that Thread.currentThread().isInterrupted() tests whether this thread has been interrupted without affecting the interrupted status.

Now, let's get back to our case. So, we know that the thread was interrupted since we caught InterruptedException, but the interrupted status was cleared by  Thread.interrupted(). This means also that the caller of our code will not be aware of the interruption.

It is our responsibility to be good citizens and restore the interrupt by calling the interrupt() method. This way, the caller of our code can see that an interrupt was issued and act accordingly. The correct code could be as follows:

try {
   queue.poll(3000, TimeUnit.MILLISECONDS);
} catch (InterruptedException ex) {
   ...
   Thread.currentThread().interrupt(); // restore interrupt
}
As a rule of thumb, after catching  InterruptedException, do not forget to restore the interrupt by calling   Thread.currentThread().interrupt().

Let's tackle a problem that highlights the case of forgetting to restore the interrupt. Let's assume a Runnable that runs as long as the current thread is not interrupted (for example,  while (!Thread.currentThread().isInterrupted()) { ... } ).

At each iteration, if the current thread interrupted status is false, then we try to get an element from BlockingQueue.

The following code is the implementation:

Thread thread = new Thread(() -> {

   // some dummy queue
   TransferQueue<String> queue = new LinkedTransferQueue<>();

   while (!Thread.currentThread().isInterrupted()) {
      try {
         logger.info(() -> "For 3 seconds the thread "
            + Thread.currentThread().getName()
            + " will try to poll an element from queue ...");

         queue.poll(3000, TimeUnit.MILLISECONDS);
      } catch (InterruptedException ex) {
         logger.severe(() -> "InterruptedException! The thread "
            + Thread.currentThread().getName() + " was interrupted!");

         Thread.currentThread().interrupt();
      }
   }

   logger.info(() -> "The execution was stopped!");
});


As a caller (another thread), we start the above thread, sleep for 1.5 seconds, just to give time to this thread to enter in the poll() method, and we interrupt it. This is shown in the following code:

thread.start();
Thread.sleep(1500);
thread.interrupt();


This will lead to InterruptedException.

The exception is logged and the interrupt is restored.

At the next step, while  evaluates Thread.currentThread().isInterrupted()  to  falseand exits.

As a result, the output will be as follows:

[18:02:43] [INFO] For 3 seconds the thread Thread-0
                  will try to poll an element from queue ...

[18:02:44] [SEVERE] InterruptedException!
                    The thread Thread-0 was interrupted!

[18:02:45] [INFO] The execution was stopped!


Now, let's comment on the line that restores the interrupt:

...
} catch (InterruptedException ex) {
   logger.severe(() -> "InterruptedException! The thread "
      + Thread.currentThread().getName() + " was interrupted!");

   // notice that the below line is commented
   // Thread.currentThread().interrupt();
}
...


This time, the while block will run forever since its guarding condition is always evaluated to true.

The code cannot act on the interruption, so the output will be as follows:

[18:05:47] [INFO] For 3 seconds the thread Thread-0
                  will try to poll an element from queue ...

[18:05:48] [SEVERE] InterruptedException!
                    The thread Thread-0 was interrupted!

[18:05:48] [INFO] For 3 seconds the thread Thread-0
                  will try to poll an element from queue ...
...
As a rule of thumb, the only acceptable case when we can swallow
an interrupt (not restore the interrupt) is when we can control the entire call stack (for example, extend Thread).
Otherwise, catching  InterruptedException should contain
  Thread.currentThread().interrupt() as well.

Done! The complete code is available on GitHub.

If you enjoyed this article, then I am sure that you will love my book Java Coding Problems, which contains two chapters dedicated to Java concurrency problems.

Further Reading

Java Thread Tutorial: Creating Threads and Multithreading in Java

Intricacies of Multi-Threading in Java

code style

Opinions expressed by DZone contributors are their own.

Related

  • Open Source: A Pathway To Personal and Professional Growth
  • Enhancing Software Quality with Checkstyle and PMD: A Practical Guide
  • Linting Excellence: How Black, isort, and Ruff Elevate Python Code Quality
  • Mastering GitHub Copilot: Top 25 Metrics Redefining Developer Productivity

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!