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

Because the DevOps movement has redefined engineering responsibilities, SREs now have to become stewards of observability strategy.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Related

  • Introducing Graph Concepts in Java With Eclipse JNoSQL, Part 3: Understanding Janus
  • Introducing Graph Concepts in Java With Eclipse JNoSQL, Part 2: Understanding Neo4j
  • How to Introduce a New API Quickly Using Micronaut
  • Introducing Graph Concepts in Java With Eclipse JNoSQL

Trending

  • Introducing Graph Concepts in Java With Eclipse JNoSQL, Part 2: Understanding Neo4j
  • How to Merge HTML Documents in Java
  • Monoliths, REST, and Spring Boot Sidecars: A Real Modernization Playbook
  • Simpler Data Transfer Objects With Java Records
  1. DZone
  2. Coding
  3. Java
  4. How to Handle an InterruptedException

How to Handle an InterruptedException

Checked InterruptedException in Java is a constant source of pain for many of us; here is my understanding of how it should be handled.

By 
Yegor Bugayenko user avatar
Yegor Bugayenko
·
Oct. 20, 15 · Tutorial
Likes (18)
Comment
Save
Tweet
Share
80.4K Views

Join the DZone community and get the full member experience.

Join For Free

InterruptedException is a permanent source of pain in Java, for junior developers especially. But it shouldn't be. It's a rather simple and easy-to-understand idea. Let me try to describe and simplify it.

Let's start with this code:

while (true) {
  // Nothing
}

What does it do? Nothing, it just spins the CPU endlessly. Can we terminate it? Not in Java. It will only stop when the entire JVM stops, when you hit Ctrl-C. There is no way in Java to terminate a thread unless the thread exits by itself. That's the principle we have to have in mind, and everything else will just be obvious.

Let's put this endless loop into a thread:

Thread loop = new Thread(
  new Runnable() {
    @Override
    public void run() {
      while (true) {
      }
    }
  }
);
loop.start();
// Now how do we stop it?

So, how do we stop a thread when we need it to stop?

Here is how it is designed in Java. There is a flag in every thread that we can set from the outside. And the thread may check it occasionally and stop its execution. Voluntarily! Here is how:

Thread loop = new Thread(
  new Runnable() {
    @Override
    public void run() {
      while (true) {
        if (Thread.interrupted()) {
          break;
        }
        // Continue to do nothing
      }
    }
  }
);
loop.start();
loop.interrupt();

This is the only way to ask a thread to stop. There are two methods that are used in this example. When I call loop.interrupt(), a flag is set to true somewhere inside the thread loop. When I call interrupted(), the flag is returned and immediately set to false. Yeah, that's the design of the method. It checks the flag, returns it, and sets it to false. It's ugly, I know.

Thus, if I never call Thread.interrupted() inside the thread and don't exit when the flag is true, nobody will be able to stop me. Literally, I will just ignore their calls to interrupt(). They will ask me to stop, but I will ignore them. They won't be able to interrupt me.

Thus, to summarize what we've learned so far, a properly designed thread will check that flag once in a while and stop gracefully. If the code doesn't check the flag and never calls Thread.interrupted(), it accepts the fact that sooner or later it will be terminated cold turkey, by clicking Ctrl-C.

Sound logical so far? I hope so.

Now, there are some methods in JDK that check the flag for us and throw InterruptedException if it is set. For example, this is how the method Thread.sleep() is designed (taking a very primitive approach):

public static void sleep(long millis)
  throws InterruptedException {
  while (/* You still need to wait */) {
    if (Thread.interrupted()) {
      throw new InterruptedException();
    }
    // Keep waiting
  }
}

Why is it done this way? Why can't it just wait and never check the flag? Well, I believe it's done for a good reason. And the reason is the following (correct me if I'm wrong): The code should either be bullet-fast or interruption-ready, nothing in between.

If your code is fast, you never check the interruption flag, because you don't want to deal with any interruptions. If your code is slow and may take seconds to execute, make it explicit and handle interruptions somehow.

That's why InterruptedException is a checked exception. Its design tells you that if you want to pause for a few milliseconds, make your code interruption-ready. This is how it looks in practice:

try {
  Thread.sleep(100);
} catch (InterruptedException ex) {
  // Stop immediately and go home
}

Well, you could let it float up to a higher level, where they will be responsible for catching it. The point is that someone will have to catch it and do something with the thread. Ideally, just stop it, since that's what the flag is about. If InterruptedException is thrown, it means someone checked the flag and our thread has to finish what it's doing ASAP.

The owner of the thread doesn't want to wait any longer. And we must respect the decision of our owner.

Thus, when you catch InterruptedException, you have to do whatever it takes to wrap up what you're doing and exit.

Now, look again at the code of Thread.sleep():

public static void sleep(long millis)
  throws InterruptedException {
  while (/* ... */) {
    if (Thread.interrupted()) {
      throw new InterruptedException();
    }
  }
}

Remember, Thread.interrupted() not only returns the flag but also sets it to false. Thus, once InterruptedException is thrown, the flag is reset. The thread no longer knows anything about the interruption request sent by the owner.

The owner of the thread asked us to stop, Thread.sleep() detected that request, removed it, and threw InterruptedException. If you call Thread.sleep(), again, it will not know anything about that interruption request and will not throw anything.

See what I'm getting at? It's very important not to lose that InterruptedException. We can't just swallow it and move on. That would be a severe violation of the entire Java multi-threading idea. Our owner (the owner of our thread) is asking us to stop, and we just ignore it. That's a very bad idea.

This is what most of us are doing with InterruptedException:

try {
  Thread.sleep(100);
} catch (InterruptedException ex) {
  throw new RuntimeException(ex);
}

It looks logical, but it doesn't guarantee that the higher level will actually stop everything and exit. They may just catch a runtime exception there, and the thread will remain alive. The owner of the thread will be disappointed.

We have to inform the higher level that we just caught an interruption request. We can't just throw a runtime exception. Such behavior would be too irresponsible. The entire thread received an interruption request, and we merely swallow it and convert it into a RuntimeException. We can't treat such a serious situation so loosely.

This is what we have to do:

try {
  Thread.sleep(100);
} catch (InterruptedException ex) {
  Thread.currentThread().interrupt(); // Here!
  throw new RuntimeException(ex);
}

We're setting the flag back to true!

Now, nobody will blame us for having an irresponsible attitude toward a valuable flag. We found it in true status, cleared it, set it back to true, and threw a runtime exception. What happens next, we don't care.

I think that's it. You can find a more detailed and official description of this problem here: Java Theory and Practice: Dealing With InterruptedException.

Java (programming language)

Published at DZone with permission of Yegor Bugayenko. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Introducing Graph Concepts in Java With Eclipse JNoSQL, Part 3: Understanding Janus
  • Introducing Graph Concepts in Java With Eclipse JNoSQL, Part 2: Understanding Neo4j
  • How to Introduce a New API Quickly Using Micronaut
  • Introducing Graph Concepts in Java With Eclipse JNoSQL

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!