- Java Program to Use Exceptions with Thread
- How to Handle the InterruptedException Checked Exception in Java
- InterruptedException Exception: What, Why & How?
- How to handle the InterruptedException Exception
- Scenario #1: Throwing InterruptedException
- Scenario #2: Catching InterruptedException (the correct way)
- Scenario #2.1 (Catch & Crash)
- Scenario #2.2 (Catch & Proceed)
- Summary
- Track, Analyze and Manage Errors With Rollbar
Java Program to Use Exceptions with Thread
Exceptions are the events that occur due to the programmer error or machine error which causes a disturbance in the normal flow of execution of the program. When a method encounters an abnormal condition that it can not handle, an exception is thrown as an exception statement. Exceptions are caught by handlers(here catch block). Exceptions are caught by handlers positioned along with the thread’s method invocation stack. If the calling method is not prepared to catch the exception, it throws the exception up to its calling method and so on. So in the java program exception handlers should be positioned strategically, so the program catches all the exception from which the program want to recover.
Lifecycle of a thread: The class implements a Thread class or Runnable interface then the extended class has start() method run the thread, sleep() methods cause the currently executing thread to sleep for the specified number of milliseconds, and many more.
Prior to discussing the approaches, state. transactions of thread should be known to further deal with exceptions for better understanding. A thread in Java at any point in time exists in any one of the following states. A thread lies only in one of the shown states at any instant:
- New
- Runnable
- Blocked
- Waiting
- Timed Waiting
- Terminated
1. A class name RunnableThread implements the Runnable interface which gives the run( ) method executed by the thread. The object of this class is now runnable
2. The Thread constructor is used to create an object of RunnableThread class by passing the runnable object as a parameter.
3. The start() method is invoked on the Thread object as it returns immediately once a thread has been spawned.
4. The thread ends when the run( ) method ends which is to be normal termination or caught exception.
5. Now in order to create a new thread
runner = new Thread(this,threadName) ;
6. In order to start the new thread.
7. public void run( ) is an overridable method used to display the information of a particular thread.
8. Thread.currentThread().sleep(2000) is used to deactivate the thread until the next thread started execution or used to delay the current thread.
Uncaught exception handler will be used to demonstrate the use of exception with thread. It is a specific interface provided by Java to handle exception in the thread run method.
There are two methods to create a thread:
- Extend the thread Class (java.lang.thread)
- Implement Runnable Interface (java.lang.thread)
1. Exception and Exception handling with threads
Here, a new thread is created in the class which is extending the thread class in which run() method is overridden. This invokes the entry point of the new thread created in the class which was extending the thread class. Further, start() method is used to start and run the thread in the program.
How to Handle the InterruptedException Checked Exception in Java
Threads are a basic concept in concurrent and parallel programming [1]. They allow programs to do multiple things at the same time and are often used for performing computationally intensive tasks in the background without interrupting the main program. This is accomplished through multithreading, a common programming and execution model which allows multiple threads to exist within the context of one process. These threads share resources but are able to execute independently.
In Java, threads are lightweight [2], which means they run in the same memory context and the time it takes to switch between threads is very short. This also means that inter-thread communication is fast and simple. Each and every Java application has a special thread created by the Java Virtual Machine, called the main thread, which is initiated by the main() method as the application’s entry point. From there, it is possible to have many user threads created and controlled from within the application, able to execute portions of the program code in parallel with the main thread.
The conventional way to create a thread in Java is by utilizing the Thread class [3], often used in conjunction with the Runnable interface [4]. Threads can be started, stopped, suspended, or otherwise switched between their life-cycle states [5]. In addition, Java threads can also be interrupted.
InterruptedException Exception: What, Why & How?
InterruptedException (from java.lang.InterruptedException ) is a checked exception [6] which directly extends java.lang.Exception . This exception is thrown when a thread is waiting, sleeping, or otherwise occupied, and the thread is interrupted, either before or during the activity [7]. If an InterruptedException is caught it means that the Thread.interrupt() method is called by some code, somewhere, on the currently running thread of the program. As a matter of fact, the only thing that can interrupt a thread is a call to Thread.interrupt() [8].
Behind the scenes, Java’s interrupt mechanism is implemented with an internal flag denoting a thread’s interrupt status. Invoking Thread.interrupt() sets this flag. To check the interrupt status of a specific thread, the Thread.isInterrupted() instance method can be used. The static method Thread.interrupted() can be invoked to observe and clear the interruption status of the current thread; the thread can then be interrupted again at any point, including immediately after clearing/unsetting its interrupt status.
By convention, any method that exits by throwing an InterruptedException clears the interrupt status of the calling thread. And it is always possible to set the interrupt status afterwards, by another thread invoking Thread.interrupt() .
How to handle the InterruptedException Exception
For simple, single-threaded programs, no special handling of this exception is necessary, so long as the code is never calling Thread.interrupt() either directly, or indirectly (through another method). However, understanding the InterruptedException exception is important, as handling it incorrectly may lead to code that’s difficult to manage and behaves poorly when executed in concurrent environments.
When calling a method that throws an InterruptedException , the main question to ask is whether it is possible and sensible to (re)throw the InterruptedException exception or not. The answer to this question then dictates what ought to be done.
Scenario #1: Throwing InterruptedException
It is often very difficult to ascertain that a running thread will never be interrupted. This is especially true when writing code that depends on external resources (e.g. network calls to external APIs) or is meant to be executed by some thread-management mechanism such as an Executor [9]. In this type of scenario, it is critical that the code responds promptly and cleanly to interrupts, so as to avoid an application from stalling or spurring a deadlock.
The best solution here is to let the InterruptedException propagate through the method call stack, by appending each relevant method signature with the throws InterruptedException statement. This might seem like an easy cop out solution at first glance, but it is, in fact, the correct solution.
// let the caller determine how to handle the interrupt public double longRunningMethod() throws InterruptedException < // any InterruptedException thrown below will be propagated double x = someExternalAPI.calculateValueOfX(); double y = anotherExternalAPI.calculateValueOfY(); return x * y; >
Scenario #2: Catching InterruptedException (the correct way)
There are situations where handling the exception with a try-catch block is the right way to go. This usually holds when either of the following is true:
- it is known in advance that the InterruptedException exception will not, and therefore should not, be encountered; or
- there is a possibility of the InterruptedException exception occurring, but it makes more sense for the method to resolve it in a self-contained manner, without propagating it up the call stack.
In either case, it is important not to ignore or disguise the exception, by doing something like this:
// bad approach try < TimeUnit.SECONDS.sleep(1); >catch (InterruptedException ignored) <>
// ill-advised try < TimeUnit.SECONDS.sleep(1); >catch (InterruptedException e)
The above approaches should be avoided as they only suppress the exception and mask the underlying issue.
Scenario #2.1 (Catch & Crash)
If a program is expected to never throw the InterruptedException exception, such an event should be treated as a serious violation of the program’s basic assumptions, and the appropriate way to handle this scenario would look something like this:
// acceptable solution try < TimeUnit.SECONDS.sleep(1); >catch (InterruptedException e) < Thread.currentThread().interrupt(); // reset interrupt status throw new AssertionError(e); // crash with a runtime error >
The above snippet accomplishes two things. First it restores the interrupt status of the thread by invoking the Thread.currentThread().interrupt() method and allowing the caller to detect the interrupt if it needs to. Then it wraps the InterruptedException in an AssertionError , which it throws to indicate that the basic invariants of the program had been violated. This approach addresses the interrupt in a manner considerate to both the called and the calling method, by logging the fact that an interrupt has occurred and crashing the program, asserting it ran into a serious problem.
Scenario #2.2 (Catch & Proceed)
In limited cases, such as when overriding a method that doesn’t throw any checked exceptions or implementing the Runnable interface, it is sensible to account for the possibility of the InterruptedException exception being thrown, but let the program move forward without crashing. In this type of scenario, the interrupt status can be reset without raising an exception, with the expectation that the code being executed next is going to handle the interrupt. This effectively delays handling the interrupt, but it doesn’t ignore or suppress the event entirely.
// reset interrupt state and proceed without crashing public Optional getOptionalResult() < try < double result = longRunningMethod(); return Optional.of(result); >catch (InterruptedException e) < Thread.currentThread().interrupt(); return Optional.empty(); >>
Summary
Threads are an important construct in multi-threaded environments. Being a multithreaded language, Java provides different mechanisms for working with threads. One of these mechanisms is Java’s built-in thread interrupt system, whose main purpose is to provide a common, well-defined framework for allowing threads to interrupt long-running tasks in other threads in a clean and consistent manner. One key component of this system is the InterruptedException checked exception, used by Java programs to recognize and handle thread interruptions. This article explains the basic mechanism behind Java’s interrupt system and the ways in which the InterruptedException exception should and shouldn’t be handled.
Track, Analyze and Manage Errors With Rollbar
Managing Java errors and exceptions in your code is challenging. It can make deploying production code an unnerving experience. Being able to track, analyze, and manage errors in real-time can help you to proceed with more confidence. Rollbar automates error monitoring and triaging, making fixing Java errors easier than ever. Sign Up Today!