0% found this document useful (0 votes)
26 views

MultiThreading and Executor

Uploaded by

dev.jai.ak
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
26 views

MultiThreading and Executor

Uploaded by

dev.jai.ak
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 26

How can thread block?

Thread can block due to IO operation (http, db, file read write), locks, latches etc

Interruptible vs uninterruptible operation


Interruptible operations are typically blocking operations, such as waiting for input from a user or
waiting for a file to be read. When an interruptible operation is interrupted, the thread that is
performing the operation throws an InterruptedException. The thread can then choose to handle
the exception or ignore it. We can identify the interruptible methods by looking for a throws
InterruptedException in their method signatures.

Uninterruptible operations are typically non-blocking operations, such as reading from a memory
location or writing to a file. When an uninterruptible operation is interrupted, the thread that is
performing the operation does not throw an exception. However, the operation may be
unsuccessful.
Stop thread after certain time - Interrupt
https://www.baeldung.com/java-stop-execution-after-certain-time

Thread.stop
Stopping the thread causes it to unlock all of the monitors that it has locked. This happens because
of the ThreadDeath exception that propagates up the stack.

If any of the objects previously protected by these monitors were in an inconsistent state, the
inconsistent objects become visible to other threads. This can lead to arbitrary behavior that is very
hard to detect and reason about.

Why thread don’t have cancel

Interrupting a thread
There is no cancel method on thread. It’s a cooperative mechanism to stop the thread. It can only be
interrupted. It may or may not stop on interrupt. On calling interrupt it sets the isInterrupted flag to
true but we need to implement to check in the interrupted thread task if it’s interrupted then stop

Thread.interrupted() -> get the current status if thread is interrupted then it will return true and
then it will be reset. To set interrupted flag again call Thread.currentThread.interrupt(); in the catch
block. if a thread is interrupted and a flag is set, nothing else will happen until it reaches one of these
interruptible methods.

A thread that is in “waiting” state to acquire the access to synchronized block can’t be interrupted

https://stackoverflow.com/questions/17141003/why-does-threads-in-blocked-state-do-not-get-
interrupted

https://stackoverflow.com/questions/18702482/ensure-that-a-task-is-interruptible
Thread lock
https://www.baeldung.com/java-concurrent-locks#:~:text=boolean%20tryLock(long%20timeout%2C
%20TimeUnit,()%20unlocks%20the%20Lock%20instance.

Lock vs synchronized
Synchronized is implicit and locks are explicit as custom lock needs to be created. For synchronized
locks are within the same scope from starting brace to ending brace. But lock can be unlocked in
different scopes. Ideally lock should be unlocked in finally block

Synchronized
Synchronized blocks use re-entrant locks, which means if the thread already holds the lock, it can re-
acquire it without problems. a thread cannot acquire a lock owned by another thread. But a thread
can acquire a lock that it already owns. Allowing a thread to acquire the same lock more than once
enables re-entrant synchronization.

Synchronizing run()
1. The run() method is not meant to be synchronized - The run() method is a public method that is
called by the Thread class to execute the thread. Synchronizing the run() method would prevent
multiple threads from executing the same instance of the class at the same time, which could lead to
performance issues.

2. It is not necessary - In most cases, there is no need to synchronize the run() method. If you need
to synchronize access to shared data, you can do so by synchronizing the methods that access the
data, rather than synchronizing the run() method.

Here are a few alternatives to synchronizing the run() method:

1. Use a synchronized block - If you need to synchronize access to a specific section of code, you can
use a synchronized block. This will prevent multiple threads from executing the code in the block at
the same time.

2. Use a lock object - If you need to synchronize access to a shared object, you can use a lock object.
This will prevent multiple threads from accessing the object at the same time.
3. Use a concurrent data structure - If you need to share data between threads, you can use a
concurrent data structure. Concurrent data structures are designed to be accessed by multiple
threads safely.

InterruptedException
InterruptedException needs to be thrown to inform the main thread that on interruption the thread
is being stopped. Thread.sleep, Object.wait will throw interrupted exception if thread.interrupt is
called on sleeping or waiting thread

https://stackoverflow.com/questions/3976344/handling-interruptedexception-in-java

IllegalStateException
start() method on a thread can only be called once. If you try to call it twice, it will throw an
IllegalThreadStateException. This is because once the thread's run() method has been executed, the
thread is considered to be in a "dead" state and cannot be restarted.

RejectionExecutionException
If shutdown is invoked on an executor service, it will complete all the tasks which are already
submitted but new tasks are submitted again after shutdown will throw
RejectionExecutionException.

Run vs Start method on thread

Execution exception
If future.get() throws an exception propogated from executing the task submitted to executor
service, this will be wrapped in an ExecutionException so future.get() should catch
ExecutionException
Do threads share common memory?
https://stackoverflow.com/questions/1762418/what-resources-are-shared-between-threads

https://stackoverflow.com/questions/3318750/why-do-threads-share-the-heap-space

https://stackoverflow.com/questions/76862157/memory-sharing-between-threads

Join
Calling Thread.join makes the calling thread wait for the thread to finish executing. That means it will
get "blocked" on that statement and won't continue until it's done executing. Passing an argument
lets you specify a timeout, which means the calling thread will wait until the thread finishes, or give
up when the timeout passes.
In your code obj.join(500) makes your main thread do nothing and wait until the obj thread to finish,
or until 500 milliseconds passes, whichever one happens first.

https://stackoverflow.com/questions/15956231/what-does-this-thread-join-code-mean

Sleep vs Yield (Both Deprecated)


sleep() causes the thread to definitely stop executing for a given amount of time; if no other thread
or process needs to be run, the CPU will be idle (and probably enter a power saving mode).

yield() basically means that the thread is not doing anything particularly important and if any other
threads or processes need to be run, they should. Otherwise, the current thread will continue to run.

Yield like sleep does not release a lock. The yield() gives a hint that the current thread is willing to
yield its current use of a processor. The thread scheduler may or may not choose to switch to
another thread, depending on the scheduling algorithm in use.

https://stackoverflow.com/questions/6979796/what-are-the-main-uses-of-yield-and-how-does-it-
differ-from-join-and-interr

https://stackoverflow.com/questions/66183005/is-thread-yield-same-as-non-blocking-io-in-java

Object.wait
The wait() method in Java is used to temporarily suspend the execution of a thread. When a thread
calls wait() on an object, it releases the lock on the object and waits until another thread calls
notify() or notifyAll() on the same object. The thread then waits until it can re-obtain ownership of
the monitor and resumes execution.

The wait() method can be called only within a synchronized block. If the thread is not the owner of
the monitor of the object on which it calls wait(), an IllegalMonitorStateException is thrown.

The wait() method has two overloaded forms:

 wait(): This method causes the current thread to wait indefinitely until another thread
invokes the notify() method or the notifyAll() method for this object.
 wait(long timeout): This method causes the current thread to wait until another thread
invokes the notify() method or the notifyAll() method for this object, or until the specified
timeout expires. If the timeout expires, the current thread will resume execution.

wait is interruptible. Thus, the thread blocked in the wait method will immediately throw an
InterruptedException after the interrupt flag is set.

https://www.baeldung.com/java-wait-notify#:~:text=wait(long%20timeout),same%20as%20calling
%20wait().

Notify vs Notify all


If we create a custom lock (monitor) object. We can ask longest waiting thread to become runnable
when a specific condition has been met. And notify all will awake all the blocked threads unlike
notify which awakens only 1 thread.

Wait vs sleep
Sleep will not release lock but wait will release lock

Thread life cycle in thread pool


All tasks are maintained in thread safe blocking queue which the threads read from and execute the
task.

 Service.isShutdown -> true if shutdown initiated. Will execute already running as well as
queued tasks
 Serice.shutdownNow -> initiate shutdown and return all queued tasks. It will only execute
already running but NOT queued tasks
 Service.awaitTermination -> block until all task are complete or if a timeout occurs
 Service.isTerminated -> true if all tasks are complete

Thread starvation
Threads needs to wait for a very long wait time to acquire the lock and in case of unfair lock the wait
time can again increase. So eventually thread will starve off the CPU time.

Runnable vs callable
Callable can return and throw exception. Callable returns a future
Thread local
We know that all threads of an Object share it’s variables, so if the variable is not thread safe, we can
use synchronization but if we want to avoid synchronization, we can use ThreadLocal variables.
Every thread has its own ThreadLocal variable and they can use it gets () and set() methods to get
the default value or change it’s value local to Thread. ThreadLocal instances are typically private
static fields in classes that wish to associate the state with a thread.

Thread local makes sense when there is a thread pool (e.g. of 10 threads) which runs 1000 tasks
(runnable) then there will be only 10 simple date format objects instead of 1000 SDFs. It increases
memory efficiency and thread safety.

Synchronized block is not necessary as thread local are inherently thread safe. Hence it will increase
performance in multi-threaded environment.

https://stackoverflow.com/questions/817856/when-and-how-should-i-use-a-threadlocal-variable

https://stackoverflow.com/questions/1202444/how-is-javas-threadlocal-implemented-under-the-
hood

Thread state and when it goes in that state


 NEW — a new Thread instance that was not yet started via Thread.start()
 RUNNABLE — a running thread. It is called runnable because at any given time it could be
either running or waiting for the next quantum of time from the thread scheduler. A NEW
thread enters the RUNNABLE state when you call Thread.start() on it
 BLOCKED — a running thread becomes blocked if it needs to enter a synchronized section
but cannot do that due to another thread holding the monitor of this section
 WAITING — a thread enters this state if it waits for another thread to perform a particular
action. For instance, a thread enters this state upon calling the Object.wait() method on a
monitor it holds, or the Thread.join() method on another thread
 TIMED_WAITING — same as the above, but a thread enters this state after calling timed
versions of Thread.sleep(), Object.wait(), Thread.join() and some other methods
 TERMINATED — a thread has completed the execution of its Runnable.run() method and
terminated

Future
https://www.baeldung.com/java-future

Future.get() is a blocking api call

 future.cancel – will cancel the task if not picked up if picked up then there will be no effect
(jvm will only attempt to stop but there is no guarantee)
 future.isCancelled – task cancelled successfully
 future.isDone – task completed

Spring equivalent of future is Mono

Completable future
Completable future is to enable async non-blocking api call done with the help of callback. If the
below was implemented with future.get() it will block all operations and make it synchronous. First
operation in the chain has to be asynchronous. By default, the same thread which did the first async
op will perform remaining op in the chain. If we want to other thread to do subsequent op then we
can use thenApplyAsync() instead of thenApply(). This is only helpful when we have a separate
thread pool to perform the subsequent async task. If no custom thread pool is supplied it takes the
default fork join pool.

https://www.baeldung.com/java-completablefuture

https://medium.com/javarevisited/java-completablefuture-c47ca8c885af#:~:text=With%20a
%20Future%20object%2C%20you,thenAccept()%20%2C%20or%20join()%20.

Future vs completable future


https://stackoverflow.com/questions/35329845/difference-between-completablefuture-future-and-
rxjavas-observable
https://stackoverflow.com/questions/54359761/future-vs-completablefuture-for-this-use-case-
completablefuture-will-make-any

Completable future vs executor service


https://stackoverflow.com/questions/68331402/completablefuture-vs-executorservice

Try Lock
Try lock will try to acquire the lock and return true / false. Try lock without timeout does not honour
the fairness of a fair lock. To make try lock fair and not barge in, timeout of 0 should be specified
with trylock.

Try lock is good for not waiting and doing the alternate operation in case if the lock is not acquired.

Reentrant lock
Allows to call lock and unlock multiple times. Number of unlock calls has to match the number of
calls of lock. Useful for recursion scenarios. Can implement fair (first come first serve) - true / unfair
(barge in) - false lock in reentrant lock constructor.

In case of unfair lock, when thread1 release lock and thread 5 requested for lock then instead of
pushing to a thread lock queue to wait and acquire, thread 5 will directly get lock instead of thread 2
and 3 which were waiting in queue to get the lock
Reactive programming with Spring web Flux

Java Fiber thread (Project LOOM)


Light weight thread which will be where multiple light weight threads will use the OS / Kernel
threads maybe 1 per core to achieve faster execution

Condition
Condtion is created on a lock (like re-entrant lock).It is used to coordinate between multiple threads.

 Condtion.await – is a blocking to which will put the thread in wait state for the certain
condition to meet
 Condition.signal – will make longest waiting threads back to runnable signalling the
condition has been met
 Condition.signalAll – will make all the waiting threads back to runnable signalling the
condition has been met

Await will release the lock associated with the Condition. Current thread will not be able to
reacquire the lock until it has been signaled or interrupted. When a thread is signalled, it wakes up
and attempts to reacquire the lock on the object. If it is successful, it resumes execution from where
it left off before calling await().
Condition vs wait/notify
https://stackoverflow.com/questions/10395571/condition-vs-wait-notify-
mechanism#:~:text=Condition%20factors%20out%20the%20Object,use%20of%20arbitrary%20Lock
%20implementations.

Spurious wake up – Producer / Consumer problem


Condition.await should be used in while loop or predicate. This should be done coz thread in await
state can wake up even though no has called signal on it. For e.g. in producer consumer problem.
When producer is fast, it should wait for consumer and when consumer is fast and there is no data
to consume it should wait

Producer-Consumer pattern using wait / notify without blocking queue


Blocking queue is a thread safe data structure. If queue is full, it will block put op. Similarly get is
blocked on an empty queue.

With blocking queue


With locks and condition created custom blocking queue

Using wait and notify


Re-entrant ReadWriteLock
Even though read and write lock are 2 separate instances only 1 will be allowed at a time. You can
either do read (by N threads) or write (by 1 thread). Both cannot be done at the same time.

Semaphore
It is to implement permit to a restricted resource which is in limited quantity. It has acquire and
release method. E.g. In a thread pool of 10 threads permit only 3 threads to perform certain actions.
How to pass input data to thread
Via constructor of the task (runnable implementation)

Stop a thread if it exceeds 10 mins


Java threads cannot be killed. They are cooperative but we need to ask politely by calling interrupt.
Even executorService.shutdownNow calls interrupt internally. Hence there is no guarantee to stop
on showdownNow also. Same with future.cancel!

Or thread task can be completed using volatile or atomic boolean flag in runnable implementation
To schedule stopping using scheduledThreadPool

To schedule stopping using future with timeout


Countdownlatch - Get produce price from 3 sources and wait for max of 3 seconds
https://www.baeldung.com/java-countdown-latch

Achieved using countdownlatch, completable future, conditions and lock etc

Using completable future


Cyclic barrier
It is to make sure that all the threads reach barrier.await() to continue execution used to create
fairness of execution. It’s like create a starting line of a race for all the threads. All tasks should reach
at the barrier.await() to break the barrier and continue exec.
Phaser
Phaser can act as a countdown latch and cycle barrier.

Synchronous Queue
It does not hold any element and has no size at all. It directly hands of item from producer to
consumer. Its different from blocking queue in put op i.e. when the queue is empty and producer
tries to put it will still be blocked until the consumer takes the item. Once consumer calls take, then
producer will put and consumer will take it. Its for direct hand off an item from one thread to
another thread

Deadlock
The order in which threads unlock mutexes does not matter. As long as a thread unlocks a mutex
that it has locked, there will be no deadlock. However, the order in which threads lock mutexes can
cause a deadlock.

A deadlock occurs when two or more threads are waiting for each other to unlock a mutex. This can
happen if one thread locks mutex A and then waits for mutex B to be unlocked, while another thread
locks mutex B and then waits for mutex A to be unlocked. In this case, neither thread will ever be
able to unlock the mutex that it is waiting for, and both threads will be deadlocked.

To avoid deadlocks, it is important to always lock mutexes in the same order across all threads that
access those mutexes. This means that if one thread locks mutex A and then mutex B, another
thread should not lock mutex B and then mutex A. Instead, the other thread should lock mutex A
and then mutex B.
Lock types – Object vs class
Synchronized on non-static method will acquire lock on this object i.e. on the object using which
method is called

Synchronized on static method will acquire class lock

https://stackoverflow.com/questions/3718148/java-class-level-lock-vs-object-level-lock

https://stackoverflow.com/questions/72349686/is-reentrant-lock-a-object-level-lock-or-class-level-
lock

https://stackoverflow.com/questions/23261120/difference-between-class-locking-and-object-
locking-in-java
https://stackoverflow.com/questions/26675381/what-are-class-level-object-level-explicit-and-
intrinsic-locking

https://stackoverflow.com/questions/22521377/class-level-and-object-level-lock-synchronization

Data Race
Any write of type int is atomic so data will not be corrupted but in case of double or long it can be
corrupted.

Race Condition
Race condition can happen with concurrentHashMap too. To avoid this the statements should be
executed atomically using lock or using compound operation of concurrentHashmap e.g.
putIfAbsent() or computeIfAbsent().

E.g. Count++ is 3 separate instruction (read, increment, write) and is not atomic.
Execute() vs submit() in executor service

Exception handling in executor service


When actions are enclosed in tasks (such as FutureTask) either explicitly or via methods such as
submit, these task objects catch and maintain computational exceptions, and so they do not cause
abrupt termination, and the internal exceptions are not passed to this method

https://stackoverflow.com/questions/2248131/handling-exceptions-from-java-executorservice-tasks

https://medium.com/@anuragsrivastava_35144/when-exception-occurs-in-a-running-thread-
537537b295b

https://dzone.com/articles/java-handling-runtimeexception

http://www.javabyexamples.com/handling-exceptions-from-executorservice-tasks

Simple date formatter in multi-threading environment


https://stackoverflow.com/questions/6840803/why-is-javas-simpledateformat-not-thread-safe
Simple date formatter alternative
DateTimeFormatter is thread-safe, while SimpleDateFormat is not.

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

LocalDate date = LocalDate.parse("2020-01-01", formatter);

Executor service
https://www.baeldung.com/java-executor-service-tutorial

Types of thread pool in executor service


 Fixed (Static) – Have fixed thread and has a queue to hold tasks submitted to the pool
 Cached (Dynamic) – No fixed threads and no queue to hold task, instead it can hold only 1
task. If all threads are busy then it will create a new thread and add it to pool and execute
the task. Cached thread pool also will kill the threads if they are idle for more than 60s. Its
good for lot of short-lived tasks. This can create OOM issue if too many threads are created.
 Scheduled – Run task after specific delay e.g., perform some check every 10s. Tasks will be
executed based on the delay.
 SingleThreaded – Same as fixed thread pool but only with 1 thread. It recreates a new thread
if its killed due to any exception. This is to ensure that tasks are run sequentially.

Thread pool
https://www.baeldung.com/thread-pool-java-and-guava

https://stackify.com/java-thread-pools/

Fork join pool


Fork join pool is same as executor service just that all its thread has its own deque to divide task into
multiple sub task and calculate the result from it. It’s used in recursions mostly.

Forking – splitting the task to multiple sub task

Joining – joining the result from multiple sub task


Work stealing in fork join pool
When Thread 1 has multiple sub tasks in queue but thread 2’s tasks are all done and there are no
tasks pending in main queue then thread 2 will steal the sub task from thread 1s queue from the end
while thread 1 executed sub tasks from the beginning.

How is thread executor pool implemented?

How is pool maintained after run method is finished?

Executor vs thread vs parallel stream

Callable impl example

Class level vs object level locking for synchronized?

Types of lock – class (static) and object (non static)?


Out of 5 threads we want specific thread to be last thread? Wait until other threads are
finished

Waiting in executor framework?

Is executor thread better than stream parallel process? Which one to use when?

Producer consumer in various methods

Does each thread has its own data?

Do threads communicate with each other or share memory and how?

Synchronized in static method, non-static method and block

How to achieve thread safety?

Exception in completable future

Combine in completable future

Why thread group is deprecated

Why while should be used instead of if condition with await?

Should awaitTermination be followed by service.shutdown in executor (both using


together)?

Get and read java thread dumps

Synchronized this vs synchronized a custom object lock

Calling future get after shutdown? Will it work?

Is thread.sleep used in production app code?


RX Java

Latches

Atomic integer
AtomicInteger is a class in Java that provides atomic operations on an integer value. This means that
operations on the value are guaranteed to be thread-safe and will not be corrupted by concurrent
access from multiple threads.

AtomicInteger is typically used in multithreaded applications where multiple threads need to access
and update the same integer value. For example, AtomicInteger can be used to implement a counter
that is incremented by multiple threads.

Here are some examples of when to use AtomicInteger in Java:

 When you need to implement a thread-safe counter.


 When you need to implement a lock-free algorithm.
 When you need to share an integer value between multiple threads without using
synchronization.
 When you need to perform atomic operations on an integer value, such as incrementing or
decrementing the value.

Volatile keyword
Volatile is to make sure that any change done by a thread is visible to another thread. Exception
being compound operation like a++ (where there are 2 separate action fetch current value of a and
then incrementing it) where synchronized is also necessary

Atomic integer vs Volatile


AtomicInteger is to make sure that compound operation like a++ are done as a whole . This is a
replacement for volatile + synchronized

Executing 2 threads alternatively


https://www.baeldung.com/java-even-odd-numbers-with-2-threads

https://www.geeksforgeeks.org/print-even-and-odd-numbers-in-increasing-order-using-two-
threads-in-java/

https://www.javatpoint.com/java-program-to-print-even-odd-using-two-threads

https://www.linkedin.com/pulse/executing-2-threads-alternately-java-8-way-my-p-ashish-kumar-
singh/
Lock vs lockInterruptibly
https://stackoverflow.com/questions/17811544/actual-use-of-lockinterruptibly-for-a-reentrantlock

Memory Model

You might also like