A thread is a path of program execution.
All Java programs at least one thread called main thread which is started by JVM.
A thread can be created by extending thread class or by implementing runnable interface.
e.g.
package helloworld;
public class ThreadTest extends Thread {
int m;
Override
public void run() {
super.run();
for (int i = 0; i < 100; i++) {
System.out.println("m is " + m);
System.out.println("My name is " + this.toString());
synchronized (this) {
try {
this.wait(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
m++;
}
}
}
The program which creates these threads is
public class ThreadTestMain {
public static void main(String args[]) {
ThreadTest t1,t2,t3;
t1 = new ThreadTest();
t2 = new ThreadTest();
t3 = new ThreadTest();
t1.start();
t2.start();
t3.start();
}
}
And to create a thread using runnable interface, you can use a code like this
public class IntrTest implements Runnable {
2. What is the differences between a thread and a process?
Both processes and threads are independent sequences of execution. The difference is that threads (of the same process) run in a shared memory space, while processes run in separate memory spaces.
A process can have multiple threads running in it. All threads of a process share its virtual address space and system resources.
Since the threads of a process share the same memory, synchronizing the access to the shared data between threads is very important.
There are the following differences between the process and thread.
A Program in the execution is called the process whereas; A thread is a subset of the process
Processes are independent whereas threads are the subset of process.
Process have different address space in memory, while threads contain a shared address space.
Context switching is faster between the threads as compared to processes.
Inter-process communication is slower and expensive than inter-thread communication.
Any change in Parent process doesn't affect the child process whereas changes in parent thread can affect the child thread.
The java.lang.Thread class contains a static State enum – which defines its potential states. During any given point of time, the thread can only be in one of these states:
NEW – newly created thread that has not yet started the execution
RUNNABLE – either running or ready for execution but it's waiting for resource allocation
BLOCKED – waiting to acquire a monitor lock to enter or re-enter a synchronized block/method
WAITING – waiting for some other thread to perform a particular action without any time limit
TIMED_WAITING – waiting for some other thread to perform a specific action for a specified period
TERMINATED – has completed its execution
sleep is a static method which will pause the thread. It can be called from any context.
But wait is an instance method and it can be called only in synchronized block. It releases the lock on the object so that other threads can acquire the lock.
When we use the sleep() method, a thread gets started after a specified time interval, unless it is interrupted.
For wait(), we can wake the thread by calling either the notify() or notifyAll() methods on the monitor that is being waited on.
Use notifyAll() instead of notify() when you want to wake all threads that are in the waiting state. Similarly to the wait() method itself, notify(), and notifyAll() have to be called from the synchronized context.
A thread can be created by either implementing runnable interface or subclassing thread class.
Runnable interface has just one method run().
In both cases, you need to override run() method.
And to start the thread of execution, you have to call start() method in both cases.
e.g.
public class Run implements Runnable {
Override
public void run() {
System.out.println("this is run method");
}
public static void main(String args[]) {
new Thread(new Run()).start();
}
}
Here is the example of subclassing Thread class
public class ThreadTest extends Thread{
public void run() {
System.out.println("Hello from run of thread ");
}
public static void main(String args[]) {
ThreadTest th = new ThreadTest();
th.start();
}
}
Daemon threads are low priority threads created by system. e.g. Garbage collector. These threads help the user threads and they run in the background. When all the user threads are completed, JVM stops the daemon threads.
A thread can be made as daemon thread by using the method
setDaemon(boolean )
setDaemon can only be called, before the thread is started. If it is called after the thread starts running, there will be a illegal state exception.
Daemon thread inherits its daemon state from the parent. If parent is a daemon, then child will also be daemon.
To check if a thread is daemon or not, we can use isDaemon() method.
Multithreading is a process of executing multiple threads simultaneously. Multithreading is used to obtain the multitasking. It consumes less memory and gives the fast and efficient performance. Its main advantages are:
Threads share the same address space.
The thread is lightweight.
The cost of communication between the processes is low.
Threads communicate primarily by sharing access to fields and the objects reference fields refer to. But such communication may produce thread interference and memory consistency errors.
The tool needed to prevent these errors is synchronization.
Let us say we have a counter class with increment and decrement methods - to increase and decrease the counter by 1. Now if these methods are accessed by multiple threads, the methods of different threads may overlap - which may result in inconsistent values.
Thread synchronization is achieved using a synchronized method or a synchronized block.
Synchronized method: A method is prefixed with the keyword synchronized.
e.g.
synchronized void increment(){
num++;
}
synchronized void decrement(){
num--;
}
When one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object will block (suspend execution) until the first thread is done with the object. When a synchronized method exits, it automatically establishes a happens-before relationship
Synchronized blocks:
Synchronization is built around an internal entity known as the intrinsic lock or monitor lock.
Every object has an intrinsic lock associated with it. By convention, a thread that needs exclusive and consistent access to an object's fields has to acquire the object's intrinsic lock before accessing them, and then release the intrinsic lock when it's done with them. A thread is said to own the intrinsic lock between the time it has acquired the lock and released the lock. As long as a thread owns an intrinsic lock, no other thread can acquire the same lock. The other thread will block when it attempts to acquire the lock.
Unlike synchronized methods, synchronized statements must specify the object that provides the intrinsic lock:
public void addName(String name) {
synchronized(this) {
lastName = name;
nameCount++;
}
nameList.add(name);
}
Multiprocessing is running multiple processes simultaneously.
A process is a program under execution. So when we are multiprocessing, we are running many programs simultaneuosly.
A thread is path of execution within a program. A program can have multiple threads and these threads can run simultaneously - called multithreading.
class NumThread extends Thread{ public void run(){ for(int i=0;i<100;i++){ System.out.println(""+(i+1)); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } class AlphaThread extends Thread{ public void run(){ for(char ch='a';ch<='z';ch++){ System.out.println(ch); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } public class TwoThreads { public static void main(String args[]){ NumThread nth = new NumThread(); nth.start(); AlphaThread ath = new AlphaThread(); ath.start(); } }
You can create a thread either by subclassing Thread class or by implementing Runnable interface.
Thread.sleep(ms)
When we invoke the join() method on a thread, the calling thread goes into a waiting state. It remains in a waiting state until the referenced thread terminates.
e.g.
Thread t = new Thread();
...
...
t.join();
Here the main thread waits for t to terminate.
To avoid indefinite waiting by join method, we can use overloaded join() with time out period.
t.join(5000);
Here the main thread waits for maximum of 5 seconds for t to terminate. 0 as a parameter indicates wait indefinitely.
The yield() method causes the currently executing thread object to temporarily pause and allow other threads to execute.
class A implements Runnable{
public void run() {
for (int i = 0; i < 5; i++) {
// yields control to another thread every 5 iterations
if ((i % 5) == 0) {
System.out.println(Thread.currentThread().getName() + "
yielding control...");
/* causes the currently executing thread object to temporarily
pause and allow other threads to execute */
Thread.yield();
}
}
}
Here for each value of i divisible by 5, we are pausing the thread and allowing other thread to execute.
Synchronized blocks:
Synchronized blocks in Java are marked with the synchronized keyword. A synchronized block in Java is synchronized on some object. All synchronized blocks synchronized on the same object can only have one thread executing inside them at the same time. All other threads attempting to enter the synchronized block are blocked until the thread inside the synchronized block exits the block.
Synchronized method:
When a thread invokes a synchronized method, it automatically acquires the intrinsic lock for that method's object and releases it when the method returns. The lock release occurs even if the return was caused by an uncaught exception.
If the synchronized method is static method, the thread acquires the intrinsic lock for the Class object associated with the class. Thus access to class's static fields is controlled by a lock
Java has two types of threads - user threads and daemon threads.
User threads are high-priority threads. The JVM will wait for any user thread to complete its task before terminating it.
On the other hand, daemon threads are low-priority threads whose only role is to provide services to user threads.
Since daemon threads are meant to serve user threads and are only needed while user threads are running, they won't prevent the JVM from exiting once all user threads have finished their execution.
To create a daemon thread, we have to use setDaemon(true)
e.g.
NewThread daemonThread = new NewThread();
daemonThread.setDaemon(true);
daemonThread.start();
Deadlock describes a situation where two or more threads are blocked forever, waiting for each other.
A Java multithreaded program may suffer from the deadlock condition because the synchronized keyword causes the executing thread to block while waiting for the lock, or monitor, associated with the specified object.
e.g.
public class TestThread {
public static Object Lock1 = new Object();
public static Object Lock2 = new Object();
public static void main(String args[]) {
ThreadDemo1 T1 = new ThreadDemo1();
ThreadDemo2 T2 = new ThreadDemo2();
T1.start();
T2.start();
}
private static class ThreadDemo1 extends Thread {
public void run() {
synchronized (Lock1) {
System.out.println("Thread 1: Holding lock 1...");
try { Thread.sleep(10); }
catch (InterruptedException e) {}
System.out.println("Thread 1: Waiting for lock 2...");
synchronized (Lock2) {
System.out.println("Thread 1: Holding lock 1 & 2...");
}
}
}
}
private static class ThreadDemo2 extends Thread {
public void run() {
synchronized (Lock2) {
System.out.println("Thread 2: Holding lock 2...");
try { Thread.sleep(10); }
catch (InterruptedException e) {}
System.out.println("Thread 2: Waiting for lock 1...");
synchronized (Lock1) {
System.out.println("Thread 2: Holding lock 1 & 2...");
}
}
}
}
}
The above code causes a deadlock. Thread 1 holds lock 1 and waits for lock2 to be released and Thread2 holds lock2 and waits for lock1 to be released.
A thread starts execution by calling its start() method.
It is wrong to call run method instead of start method because run() will start execution of the thread within the current thread whereas
The notify() method is used for sending a signal to wake up a single thread in the waiting pool. But notifyAll() method is used for sending a signal to wake up all threads in a waiting pool.
A Thread can be created by using two ways.
By extending the Thread class
By implementing the Thread class
However, the primary differences between both the ways are given below:
By extending the Thread class, we cannot extend any other class, as Java does not allow multiple inheritances while implementing the Runnable interface; we can also extend other base class(if required).
By extending the Thread class, each of thread creates the unique object and associates with it while implementing the Runnable interface; multiple threads share the same object
Thread class provides various inbuilt methods such as getPriority(), isAlive and many more while the Runnable interface provides a single method, i.e., run().
Each thread has a priority. JVM runs threads with higher priorities over threads with lower priorities. When a thread is created, it will have the same priority as its parent thread. getPriority() returns the priority of the current thread setPriority(int pr) will set the priority of the thread. Priority values are in the range of Thread.MAX_PRIORITY to Thread.MIN_PRIORITY class T1 implements Runnable{ public void run(){ while(true){ for(int i=0;i<100;i++) System.out.println(i); } } } class T2 implements Runnable{ public void run(){ while(true){ for(char ch = 'A'; ch<='Z'; ch++) System.out.println(ch); } } } class ThrPri{ public static void main(String args[]){ Thread thread1 = new Thread(new T1()); thread1.setPriority(thread1.getPriority()+1); Thread thread2 = new Thread(new T2()); thread2.setPriority(thread2.getPriority()-1); thread1.start(); thread2.start(); } }
Under preemptive scheduling, the highest priority task executes until it enters the waiting or dead states or a higher priority task comes into existence.
Under time slicing, a task executes for a predefined slice of time and then reenters the pool of ready tasks. The scheduler then determines which task should execute next, based on priority and other factors.
But also note that Java does not force a VM to schedule threads in a specific manner or contain a thread scheduler. That implies platform-dependent thread scheduling.
If we call a run method instead of start method of a thread, then a new thread is not created. The run method of thread is executed within the existing thread itself.
So we must always call start() method of a thread. This will create a thread and start execution of this thread using run method.
Shutdown Hooks are a special construct that allows developers to plug in a piece of code to be executed when the JVM is shutting down. This comes in handy in cases where we need to do special clean up operations in case the VM is shutting down.
public class ShutDownHook
{
public static void main(String[] args)
{
Runtime.getRuntime().addShutdownHook(new Thread({
public void run()
{
System.out.println("Shutdown Hook is running !");
}
});
System.out.println("Application Terminating ...");
}
}
When we run this code, the shutdown hook will be executed when the JVM finishes execution of main method.
Please note the following
1. The shutdown hook may not get called at all - if OS gives SIGKILL or if there is an internal error which crashes the JVM, the shutdown hook code may not get executed.
2. The code of shutdown hook can be stopped in the middle only by using Runtime.halt() method is called.
3. There can be multiple shutdown hooks, but their execution order is not pre-determined.
4.If we are using Java Security Managers, then the code which performs adding/removing of shutdown hooks need to have the shutdownHooks permission at runtime.
If your code is executing in a multi-threaded environment, you need synchronization for objects, which are shared among multiple threads, to avoid any corruption of state or any kind of unexpected behavior.
Synchronization in Java will only be needed if a shared object is mutable
If your shared object is an either read-only or immutable object, then you don't need synchronization, despite running multiple threads.
Sleep method is used to pause the execution of the current thread for a given duration.
e.g.
public class Demo {
public static void main(String[] args) throws InterruptedException {
Thread.sleep(2000);
}
}
Please note that
1) Thread sleep doesn’t lose any monitors or locks current thread has acquired.
2) Any other thread can interrupt the current thread in sleep, in that case InterruptedException is thrown.
When synchronizing on a static method , the monitor belongs to the class.
That means while execution of a static method the whole class is blocked. So other static synchronized methods are also blocked. If one thread is executing a static synchronized method, all other threads trying to execute any static synchronized methods will be blocked.
class NumThread extends Thread{
public void run(){
for(int i=0;i<100;i++){
System.out.println(""+(i+1));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class NumThread2 implements Runnable {
public void run(){
for(int i=-1;i>-100;i--){
System.out.println(i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class TwoThreads {
public static void main(String args[]){
NumThread nth = new NumThread();
nth.start();
Thread ath = new Thread(new NumThread2());
ath.start();
}
}
The interrupt mechanism is implemented using an internal flag known as the interrupt status. Invoking Thread.interrupt sets this flag. When a thread checks for an interrupt by invoking the static method Thread.interrupted, interrupt status is 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. However, it's always possible that interrupt status will immediately be set again, by another thread invoking interrupt.
In programming, an atomic action is one that effectively happens all at once. An atomic action cannot stop in the middle: it either happens completely, or it doesn't happen at all. No side effects of an atomic action are visible until the action is complete.
Atomic actions cannot be interleaved, so they can be used without fear of thread interference.
If a thread performs a non-atomic operation on an object which is shared by other objects, there will be inconsistency in the state of that object. To avoid that, we need to use synchronization.
The synchronized keyword before a block means that any thread entering this block has to acquire the lock. If the lok is already acquired by another thread, the former thread will enter the BLOCKED state and wait until the lock is released.
synchronized(object) {
// ...
}
A synchronized method has the same semantics, but the instance itself acts as a lock object.
synchronized void instanceMethod() {
// ...
}
For a static synchronized method, the lock is the Class object representing the declaring class.
static synchronized void staticMethod() {
// ...
}
No
These 3 methods defined in Object class are used for thread synchronization.
wait() method pauses the current thread and waits for some other thread to invoke notify() or notifyAll() method.
The thread must own the monitor of this object.
wait() has two other variants
wait(long millisecs)
wait(long millisecs,long nanosecs)
These two variants will resume the thread after the given time has elapsed if no other thread invokes notify.
notify() : Wakes up a single thread that is waiting on this object's monitor.The choice is arbitrary.
notifyAll : Wakes up all threads that are waiting on this object's monitor. A thread waits on an object's monitor by calling one of the wait methods.
The awakened threads will not be able to proceed until the current thread relinquishes the lock on this object. The awakened threads will compete in the usual manner with any other threads that might be actively competing to synchronize on this object;
In concurrent computing, a deadlock is a state in which each member of a group of actions,
is waiting for some other member to release a lock
A livelock is similar to a deadlock,
except that the states of the processes involved in the livelock constantly change with regard to one another,
none progressing. Livelock is a special case of resource starvation; the general definition only states that a specific process
is not progressing.
A real-world example of livelock occurs when two people meet in a narrow corridor, and each tries
to be polite by moving aside to let the other pass, but they end up swaying from side to side without making any progress because
they both repeatedly move the same way at the same time.
Starvation is a situation in which a runnable process is overlooked indefinitely
by the scheduler; although it is able to proceed, it is never chosen.