April 01, 2016

Part 4: Java Thread Interview Questions & Answers (Race condition, Deprecated Methods, isInterrupted and interrupted)


What is a race condition in Java?
  • A race condition occurs when the critical section is concurrently executed by two or more threads. This can lead to incorrect behaviour of a program. 
  • We can say it is a condition in which two or more threads compete together to get certain shared resources.
  • A race condition is when multiple threads read and write the same variable i.e. they have access to some shared data and they try to change it at the same time. This results in a non-deterministic bug, which is one of the hardest bugs to find and re-produce because of the random nature of racing between threads.
There are the following two solutions to avoid race conditions.
a). Mutual exclusion: If a thread is using a shared variable or thread, another thread will exclude itself from doing the same thing.
b). Synchronize the process: A thread can prevent this from happening by locking an object. When an object is locked by one thread and another thread tries to call a synchronized method on the same object, the second thread will block until the object is unlocked.

How to stop a thread in Java?
It's easy to start a thread in Java because you have a start() method, but it's difficult to stop the thread because there is no working stop() method. There were some control methods in JDK 1.0 e.g. stop(), suspend(), and resume() which were deprecated in later releases due to potential deadlock threats

Programmers mainly rely on the fact that the thread stops automatically as soon as they finish the execution of the run() or call() method. To manually stop, programmers either take advantage of volatile Boolean variables and check in every iteration if the run method has loops or interrupt threads to abruptly cancel tasks. e.g:



Why suspend() and resume() methods are deprecated?
Suspend() method puts the thread from running to the waiting state. And thread can go from waiting to a runnable state only when the resume() method is called on the thread.

The suspend() and resume() methods of the Thread class in Java have been deprecated because they can lead to serious problems such as deadlock and other thread-related issues. These methods were part of the original Java threading mechanism, but their use has been discouraged due to their inherent dangers.

Here are some of the reasons why suspend() and resume() are deprecated:
  • Deadlock Risk: When a thread is suspended, it holds the locks it acquired before the suspension. If another thread attempts to acquire the same locks, it may be blocked indefinitely, leading to a deadlock situation.
  • Thread Starvation: If a thread is suspended and not resumed, it can cause other threads contending for the same resources to be starved, as the suspended thread is not releasing the resources it holds.
  • Inconsistent State: Suspending and resuming threads can lead to unpredictable and inconsistent program states. If the target thread holds a lock on an object when it is suspended, no thread can lock this object until the target thread is resumed. If the thread that would resume the target thread attempts to lock this monitor before calling resume, it results in deadlock formation. These deadlocks are generally called Frozen processes.
Instead of using suspend() and resume(), it is recommended to use other concurrency mechanisms and practices, such as the java.util.concurrent package, the synchronized keyword, and explicit locking with Lock objects.

Why destroy() method is deprecated?
Like suspend(), and resume() destroy() method is also deadlock prone, that's why the destroy() method in the Thread class was deprecated in Java. The destroy() is considered unsafe and could lead to unpredictable and potentially harmful behaviour. 

Here are some reasons why the destroy() method was deprecated:
  • Unsafe Termination: The destroy() method forcibly terminates a thread, without allowing it to clean up or release resources properly. This can result in inconsistent program states, resource leaks, and potential corruption of shared data.
  • Potential Deadlocks: If the target thread holds a lock on an object when it is destroyed, no thread can lock this object.
  • Security Concerns: Allowing threads to be destroyed without proper cleanup poses security risks. It can lead to vulnerabilities, as resources may not be released as expected, and the system might be left in an unpredictable state.
  • No Safe Point for Termination: Similar to the issues with suspend() and resume(), there is no guarantee that a thread will be terminated at a safe point in its execution. This lack of predictability can result in data corruption and other problems.
It's generally recommended to design threads to be responsive to interruption signals using mechanisms like interrupt() and isInterrupted() rather than forcibly terminating them. This allows threads to gracefully handle termination requests, release resources, and maintain the overall stability and reliability of the program.

Additionally, you must know calling the destroy() method on Threads throws a runtime exception i.e. NoSuchMethodError. The destroy() method puts the thread from running to a dead state.

Why Thread.stop() method is deprecated?
public final void stop() is deprecated because it's unsafe and may lead the program to some unexpected circumstances.

Thread.stop() causes the thread to release all the acquired monitors and throw a ThreadDeath error, which ultimately causes the thread to die. Since the thread releases all the acquired monitors immediately, it may leave a few objects (whose monitors were acquired by the thread) in an inconsistent state. Such objects are called damaged objects and obviously, they may result in some arbitrary behavior.

Can't the ThreadDeath object be caught and all the damaged objects be fixed after stop() is called?
Theoretically yes, but practically it's not possible as a thread may throw this ThreadDeath error almost anywhere, and what if a ThreadDeath is thrown while executing the catch or finally block of the first ThreadDeath which we just caught? and so on.

Because of this, it may soon become practically infeasible to guarantee a fixed version of all the damaged objects. This is why the designers of Java preferred to deprecate the method rather than ask the developers to do such complex and almost infeasible work to ensure damage control in all the cases while using the stop method.

Why Thread.stop(Throwable) has been deprecated?
public final void stop(Throwable obj), this variant of the stop method causes the thread to complete abnormally and to throw the passed parameter of type Throwable as an exception. This abnormal completion of the thread makes this method unsafe and potentially dangerous for the same reasons as for the other variant of the stop() method and hence it's deprecated.

In addition, this variant may require a checked exception to be thrown which the target thread may not be prepared to handle and throw. This may lead to a very awkward situation and defined behavior is probably not guaranteed in such a case.

A null value passed as the parameter will unexpectedly result in a NullPointerException in the calling thread.

What will happen if we call the stop() method on a thread which is not yet started?
In this case, when the thread starts then the stop() method causes it to die immediately.

Why is ThreadDeath a subclass of Error and not of Exception?
public class ThreadDeath extends Error - an object of this class is thrown when the Thread.stop() method is called without any argument. If a method catches this thrown object then it should re-throw the error so that the thread actually dies. This is the reason why the ThreadDeath class has been made a subclass of the Error class and not of the Exception class.

Many applications simply use the Exception type to capture all the exceptions and handle them either by simply ignoring them OR maybe by doing something in the handler. The ThreadDeath when thrown should not be handled that way. It's thrown only when Thread.stop() method is called and that simply expects the thread to die and not to be handled some other way.

What is the difference between the interrupt(),  interrupted(), and isInterrupted() methods in Java?
In Java, the interrupt(), interrupted(), and isInterrupted() methods are related to handling thread interruption, but they serve different purposes. 

The interrupt() method is used to interrupt a thread. When a thread is interrupted, it receives an interrupt signal, and its interrupt status is set to true. We call interrupt() on a Thread object to indicate that the thread should stop or respond to the interruption.

Invoking the interrupt() method just gives a hint to JVM to interrupt but it is not mandatory. That's why when we call this method thread will not be interrupted immediately.

If a thread is currently inside one of the methods that throws InterruptedException (wait, join, sleep, etc.), then the interrupted() method immediately throws InterruptedException. The thread is free to process this exception according to its own logic. If a thread is not inside such a method and thread.interrupt() is called, nothing special happens, i.e the thread will not be interrupted in the middle. That means Thread will do its job till the end. 

The interrupted() method is a static method of the Thread class that checks the interrupt status of the current thread and clears the interrupt status. It is used to check if the current thread has been interrupted and clear its interrupt status.

The isInterrupted() method is an instance method of the Thread class that checks the interrupt status of a thread but does not clear the interrupt status. It is used to check if a thread has been interrupted without clearing its interrupt status. If the flag is set, it will remain set after calling this method.

In short, the interrupted() method is static and checks/clears the interrupt status of the current thread, while isInterrupted() is an instance method and checks the interrupt status of a specific thread. Both interrupted() and isInterrupted() return a boolean value indicating whether the thread has been interrupted. The interrupt status is a flag that can be queried and cleared using these methods, and it is not automatically cleared by the system.
How do you check if a thread holds a lock or not?
holdsLock() method from java.lang.Thread, it returns true if and only if the current thread holds the monitor lock on the specified object.

If you enjoy our content and want to support us, please consider donating via gpay, phonepay or paytm on +91 9920600280. Also, I’d appreciate it if you’d buy me a coffee☕ 


Keep learning and growing!
-K Himaanshu Shuklaa..

No comments:

Post a Comment