2. What we cover in this ebook ?
1. multithreading
2. thread creation
3. thread system dependency
4. thread states
5. yielding vs spleeping
6. runnable interface
7. Interrupted Exception
8. local variables
9. volatile variables
10. volatile thread safety
11. thread interruption
12. join method
13. synchronization
14. thread interference
15. memory consistency errors
16. synchronized method
3. 1/16 Explain multithreading in Java ?
Threads in Java appear to run concurrently, so it
provides simulation for simultaneous activities.
The processor runs each thread for a short time and
switches among the threads to simulate
sim-ultaneous execution (context-switching)
and it make appears that each thread has its own
processor.
By using this feature,users can make it appear as if
multiple tasks are occurring simultaneously when, in
fact, each is running for only a brief time before the
context is switched to the next thread.
We can do other things while waiting for slow I/O
operations -> better interaction with users
4. 2/16 What are the possibilities for Thread creation ?
Each thread is associated with an instance of
the class Thread.
- direct control of thread creation and
management, simply instantiate the
Thread each time the application needs
to initiate an asynchronous task
To avoid need to control the thread
management, easiest is to pass the thread to a
thread executor
5. It is usually the operating System, which decides which thread to run when and for how much time.
But there is no guarantee when it will be run and for how long.
3/16 Are Threads in Java System dependent ?
6. 4/16 What are a Thread states ?
When a Thread is created ( Thread t = new Thread( ...);,
it is put in [New] state
Once it is started ( t.start(); ), it is in [Runnable] (but not
running) state.
JVM only looks at threads in [Runnable] state to
schedule them for execution. When the JVM executes a
Thread, it is said to be in [Running] state.
Thread acquires the intrinsic lock when it enters a
synchronized method. Thread inside the synchronized
method is set as the owner of the lock and is in
[RUNNABLE] state.
Any thread that attempts to enter the locked method
becomes [BLOCKED].
7. 5/16 Difference between Yielding and Sleeping ?
yield method - it returns Thread to the ready state.
sleep method - it returns Thread to the waiting state.
8. 6/16 Why do we need Thread class even in case we
execute thread using runnable interface ?
Thread class holds the definition of start method
( This is the method that starts execution of new thread and then calls run
method within the scope of new thread ).
Interfaces don't hold any definition and so does runnable.
So it makes it necessary the usage of Thread class , whatever implementation you choose.
When your class extends the thread class, it carries the definition of start method from parent Thread
class onto itself and hence new yourClass.start() helps starting a new thread and then executing run
method in that new thread scope.
When you implement runnable interface , you are just making it sure to the JVM that you have
implemented the required method ( run() ) which the Thread start method will look for upon executing
start method.
9. 7/16 How to handle InterruptedException
(unchecked exception) properly ?
InterruptedException is thrown by Thread.interrupt()
Example: if your Runnable objects are executed using an ExecutorService and shutdownNow() is called
on the service
Use the InterruptedException to exit whatever looping you're doing, or you can catch the exception and
restore the interrupt flag so that the next check of the interrupt flag (using
Thread.currentThread().isInterrupted()) can see that the thread has been interrupted:
10. 8/16 Are local objects and variables thread safe ?
Local variables are stored in each thread's own stack , so they are:
- never shared between threads.
- thread safe.
But Local object references :
- the reference itself is not shared among threads , stored on thread stack
- the object itself is stored on a shared heap
If an object created locally never escapes the method it was created in -> it is thread safe.
In fact you can also pass it on to other methods and objects as long as none of these methods
or objects make the passed object available to other threads.
11. 9/16 What is Volatile variable ?
Reads operation and write operation (separately) are atomic for :
- reference variables and for most primitive variables (all types except long and
double).
- all variables declared volatile (including long and double variables).
12. 9/16 What are Volatile variable ?
In case one thread reads and writes the value of a volatile variable,
and other threads only read the variable, -> then the reading threads
are guaranteed to see the latest value written to the volatile variable. (
Without making the variable volatile, this would not be guaranteed)
The value of volatile variable will never be cached thread-locally:
all reads and writes will go straight to "main memory" , which is slower
vs cpu cache
If two threads are both reading and writing to a shared variable, then
using the volatile keyword for that is not enough (no lock). You need
to use synchronization in that case to guarantee that the reading and
writing of the variable is atomic.
13. 10/16 Is volatile variable thread safe ?
Accessing a volatile variable never holds a lock, so it is not suitable for cases where we want to
read-update-write as an one atomic operation
Volatile fixes thread-visibility problem but it does not deal with atomicity.
Volatile will prevent compiler to reorder the instruction which involves write and subsequent
read of a volatile variable.
But k++ is not a single machine instruction rather it is three machine instructions:
- copy the value to register
- increment it
- place it back
So even though you declare variable to volatile it will not make this operation atomic that
means another thread can see a intermediate result.
14. 11/16 What is thread interruption ?
The interrupt mechanism is implemented using an internal flag
known as the interrupt status.
Invoking Thread.interrupt() sets this flag.
When a thread is interrupted by invoking the static method
Thread.interrupted() -> interrupts and makes interrupt status
cleared.
The non-static isInterrupted() method, which is used by one thread
to query the interrupt status of another, does not change the
interrupt status flag.
By convention, any method that exits by throwing an
InterruptedException clears interrupt status when it does so.
15. 12/16 What is thread join method ?
The join method allows one thread to wait for the
completion of another.
If t is a Thread object whose thread is currently
executing,
t.join();
t.join(1000);
//wait 1 sec, after 1 sec continue on
causes the current thread to pause execution until t
thread terminates.
16. 13/16 Why do we need to synchronize code ?
Synchronization can introduce thread contention, which occurs when
two or more threads try to access the same resource simultaneously
and cause the Java runtime to execute one or more threads more
slowly, or even suspend their execution.
Starvation and livelock are forms of thread contention.
synchronized keyword can be applied only to a
- non-abstract method
- method block of code
- static or instance initialization block
17. When two operations, running in different threads, but acting on the same data, interleave.
This means that the two operations consist of multiple steps, and the sequences of steps overlap.
If two threads call the increment() method on the same Counter instance simultaneously,
We could see either : 00 or 01 Since access to count is not synchronized, there is no guarantee that
changes made by thread 1 will even be visible to thread 2.
Thus, both the threads may print 0 and increment it to 1 even if they run one after the other.
//Decomposition of count++
1 Retrieve the current value of count.
2 Increment the retrieved value by 1.
3 Store the incremented value back in count.
14/16 What is thread Interference ?
18. 15/16 What is the memory consistency error ?
Can occur when different threads have inconsistent views of what should be the same data.
All that is needed is a strategy for avoiding them = create happens-before relationships,
One of them is synchronization
19. 16/16 How does Synchronized method work ?
- A synchronized method is similar to any other method except that only one thread per each
instance can be in this method at once.
- A thread can enter a synchronized method only after it acquires a lock.
Note that acquiring a lock is necessary only for entering synchronized methods,
there is no need to get a lock (of the object on which it is trying to execute the method)
for entering a normal method.
- This means if Thread T1 is in a synchronized method sM1() then
Thread T2 can enter any other non-synchronized method.
But T2 CANNOT enter sM1() or any other synchronized method because there is only one
lock with one object which is already taken by T1, so if they want to access they are blocked.
20. 16/16 When do we use Synchronized method ?
When no thread contention -> can use synchronized for performance
When any contention -> use StampedLock as it is better in throughput
21. 16/16 What happens when the thread wants to call 2
synchronized methods ?
A thread can re-acquire a lock. This means once it enters a synchronized method sm1() it can call
any other synchronized method within it. -> no deadlock.
When a synchronized method exits,
it automatically establishes a happens-before relationship with any subsequent invocation of a
synchronized method for the same object.
This guarantees that changes to the state of the object are visible to all threads.