What are deadlock, livelock, and starvation? What causes these conditions?
Deadlock describes a situation where two more threads are blocked because of waiting for each other forever. When deadlock occurs, the program hangs forever and the only thing you can do is to kill the program.
Livelock describes situation where two threads are busy responding to actions of each other. They keep repeating a particular code so the program is unable to make further progress:
- Thread 1 acts as a response to action of thread 2
- Thread 2 acts as a response to action of thread 1
Unlike deadlock, threads are not blocked when livelock occurs. They are simply too busy responding to each other to resume work. In other words, the program runs into an infinite loop and cannot proceed further.
Starvation describes a situation where a greedy thread holds a resource for a long time so other threads are blocked forever. The blocked threads are waiting to acquire the resource but they never get a chance.
Thus they starve to death.
Starvation can occur due to the following reasons:
- Threads are blocked infinitely because a thread takes long time to execute some synchronized code (e.g. heavy I/O operations or infinite loop).
- A thread doesn’t get CPU’s time for execution because it has low priority as compared to other threads which have higher priority.
- Threads are waiting on a resource forever but they remain waiting forever because other threads are constantly notified instead of the hungry ones.
When a starvation situation occurs, the program is still running but doesn’t run to completion because some threads are not executed.
What happens if you don’t override the thread class run() method?
- In Thread class, run() method is defined with an empty implementation.
- If we override run() method in the user-defined thread then in run() method we will define a job and Our created thread is responsible to execute run() method.
- It is highly recommended to override run() method because it improves the performance of the system.
- If we don't override Thread class run() method in our defined thread then Thread class run() method will be executed and we will not get any output because Thread class run() is with an empty implementation.
What is atomic operation and what are atomic classes in the Java Concurrency API?
An atomic operation is an operation which is performed as a single unit of work without the possibility of interference from other operations. The Java language specification guarantees that reading or writing a variable is an atomic operation (unless the variable is of type long or double).
The most commonly used atomic variable classes in Java are AtomicInteger, AtomicLong, AtomicBoolean, and AtomicReference. These classes represent an int, long, boolean, and object reference respectively which can be atomically updated.
What are Executor and ExecutorService and what are the differences between them?
The main difference between Executor, ExecutorService, and Executors class is that Executor is the core interface which is an abstraction for parallel execution. ... It also provides a submit() method which extends Executor. execute() method and returns a Future.
What are Concurrent Collection Classes?
Concurrent collections in java are designed and optimized specifically for synchronized multithreaded access. These are the thread safe collections, and these are existing in java.util.concurrent package.
Some Java Concurrent collection classes are:
- Immutable List - read-only. You can’t modify the content of the immutable List after declaration. So an immutable list is threaded safe.
- CopyOnWriteArrayList - is a thread-safe version of ArrayList. Multiple threads can read the data but only one thread can write the data at one time.
- Immutable Set - can have a collection of objects like HashSet but we can’t modify the objects of the immutable set. If we try to add or remove any object in immutable set it throws UnsupportedOperationException.
- CopyOnWriteArraySet - extends the AbstractSet class and implements the Serializable interface: well suited if you have small size collection and want to perform only read operation by multiple threads.
- ConcurrentHashMap - is the concurrent version of the HashMap. It internally maintains a HashTable that is divided into segments. The number of segments depends upon the level of concurrency required the Concurrent HashMap. By default, it divides into 16 segments and each Segment behaves independently. It doesn’t lock the whole HashMap as done in HashTables/SynchronizedMaps, it only locks the particular segment of HashMap.
No comments:
Post a Comment