Table of Contents
Define thread in Java
Thread is a flow of execution through the process code and the process can contain multiple threads which is known as Multi-threading. Basically its a multiple flow of execution. So running multiple task at a certain time. This is where most of the people misunderstood, let’s say there is a process which runs for 10 minutes and there is no guarantee that creating ten threads for this process will cut down the time to one minute, because there maybe dependent tasks that can be run in a program. But time can be cut down up to 7 or 8 seconds and it depends on the process. Threads used to perform complicated tasks in the background without disturbing the main process.
There are 2 type of multi-threading as shown in the above diagram. In Process based, lets say for example, programmers usually listen to music while coding and sometimes they may be downloading any documents from the internet, which means, they are doing multiple things on the same time. These tasks are independent, it won’t affect any of them if one of the above processes were closed. In Thread based multitasking, each and every threads are belongs to a same main process. Usually a single main thread will be divided into multiple tasks. lets say there are 100 files to be processed for 100 minutes. By using two threads, these process might be finished in less than 100 minutes. But there is no way by increasing the number of threads will help to complete the task in 1 second or in no time. Because there is no point in taking a same file and processing again and again. This explanation is just for the clarification not the exact real life scenario and its just a basic idea of what is a thread and their limitations.
Thread Life Cycle
1: What is the default value of a boolean in Java?
New
This the state where the thread is created.
Ready/Runnable
When the start()
method is invoked to a particular thread, it will switch state from New to Ready or Runnable state
Running
The Thread will switch to Running state when run()
method is invoked. which means when the process is executing. But it may go back to Ready/Runnable state and come back to Running state and this can happen again and again also.
Blocked
This is the state where one thread blocked on the lock because other thread has already acquired this lock.
Waiting
In this state, the thread will wait forever until if there is any interruption. Usually the invocation of join()
or wait()
method will put the thread in waiting state.
Timed Waiting
When sleep()
method or join()
or wait()
methods with timeout are invoked, that state is known as Timed Waiting. Name itself explains that the the thread will wait for a certain given time.
Dead
This state represents the completion of process.
Learn to code from industry experts! Enroll here
How to create a Thread in Java ?
In Java thread can be created by two ways,
- By Extend Thread class
- By Implement Runnable Interface
lets check it one by one,
Extending Thread class
Here, I am going to use 2 classes. So to create a thread, we need to extend the Printer class with the Thread class as shown in the code below.
Now to run the thread, we have to create an instance of the Thread class in the main method of the Application class and invoke that start()
to that instance as I mentioned in the code below.
So If I run the application I will get the output as,
Main thread is running....
Child thread is running....
Facts about creating thread by Extending Thread class
- It is not must to override the run method in Thread class. Lets see why, when I call the
start()
it will check the Printer thread. Since I don’t have thestart()
method there, it will check the parent class witch is Thread class. In Thread class there will be astart()
and that invokesrun()
method. So when calling run method it will the printer Thread class, since it doesn’t has therun()
method, it will check the Thread class and it doesn’t do anything. Inside that run method, if the target is set then it will executetarget.run()
method. In our case we don’t have any target so it’s just don’t do anything. thats the reason it worked.
So If we are not overriding the run method which means we are not doing any tasks, because all the process of threads have to go torun()
method. This is only valid when we are Extend the Thread class. But when we implement the runnable interface, java program will force you to override therun()
method. Because that’s the behavior of the runnable interface which we are going to look next. - As you can see from the above code snippet, even though the
start()
method invoked(in line number 7 on the Application class) before printing the sentence in the main thread, it was printed after the main thread prints. which means, there is no guarantee that invokingstart()
method will immediately run the thread and it is entirely depend on the JRE(based on the OS). In the previous point, I mentioned abouttarget
which is a runnable object. In our case printer object, so if it hasrun()
method then it will execute it and if not it will got the super class and execute therun()
method as I said before.
lets see some example of thread,
so in this child thread this should print from 1 to 10.
and in the main thread this should print from 1 to 100
So I run this program several time to test the result.
1st time output
Main thread is running....
Child thread is running....
main 0
child 0
child 1
main 1
main 2
main 3
child 2
main 4
child 3
main 5
child 4
main 6
.
.
2nd time output
Main thread is running....
Child thread is running....
child 0
main 0
main 1
main 2
child 1
main 3
child 2
main 4
child 3
main 5
child 4
main 6
.
.
3rd time output
Main thread is running....
Child thread is running....
child 0
main 0
child 1
main 1
child 2
main 2
child 3
main 3
child 4
main 4
child 5
main 5
child 6
main 6
.
.
So from the above results, each execution has different orders, so this gave a conclusion, that there is no guarantee the thread will start immediate whenever the start()
method is invoked. Its because of the Thread Scheduler and this decides which thread should run (order) and its entirely depends on JRE (OS based) as I mentioned above.
- What will happen if we override the
start()
method in the Thread class?
Yes, but lets say we are invokingstart()
method inPrinter class
, what it does is, it will look for the immediate class and it has the method so it will run and it won’t go to the super class to create a thread. So is there any way to create the thread even overriding thestart()
method? answer is yes we can, by simply puttingsuper.start()
inside thestart()
method of the Printer class. - What will happen if we overload the
run()
method?
Yes, but Thread classes’ start method always invoke with the no arguments. - Most of the programmers think that the java program will terminate once the main thread terminates. But in reality its not a daemon thread so the child thread can actually continue. what we can do is, we can change the printer thread object to a daemon thread by giving
printer.setDaemon(true);
in the main class. At this point when you run the program, when the main thread ends the child thread also suppose to end but you may notice that the child thread will run for a certain period of time even after the main thread ends because at the moment when the main thread printing the last line, the child thread already processed up to certain values and the delay is occurred because of the time taken to print. - The main disadvantage of this method is, we will loose the hierarchy of the classes when we extend Thread class to that particular class because Java does not support multiple inheritances.
Implement Runnable Interface
In the above code we have used implements Runnable instead of extending from Thread class.
Runnable interface is a SAM (Single Abstract Method) which has a single method called run and thats it. In this case we don’t have intermediate Thread class so we don’t have someone to implement the run()
method. So what we did here is, We create an instance from a Thread class (which means we can pass Runnable instance to that as I mentioned in the previous thread creating method and also to give thread behavior) called thread
and I pass the object printer
as the parameter to the thread instance. Now printer
is a Runnable class. That is why I invoked the start method from thread instance. And I got the output as follows,
Main thread is running....
Child thread is running....
main main 0
child 0
main main 1
child 1
main main 2
child 2
main main 3
child 3
child 4
child 5
main main 4
child 6
main main 5
child 7
main main 6
child 8
main main 7
child 9
main main 8
child 10
main main 9
child 11
Main thread Ends here
child 12
child 13
child 14
child 15
child 16
child 17
child 18
child 19
===========================
So this is the method of creating thread in the second approach.
There are eight constructors in the Thread class such as,
- Thread()
Thread T1 = new Thread();
- Thread(Runnable target)
Thread T2 = new Thread(printer);
- Thread(String name)
Thread T3 = new Thread(name:"printerThread");
- Threat(Runnable target, String name)
Thread T4 = new Thread(printer, name:"printerThread");
- Thread(ThreadGroup group, String name)
Thread T5 = new Thread(new ThreadGroup(),name:"printerThread");
- Thread(ThreadGroup group, Runnable target)
Thread T6 = new Thread(new ThreadGroup(),printer);
- Thread(ThreadGroup group, Runnable target, String name)
Thread T7 = new Thread(new ThreadGroup(),printer,name:"printerThread");
- Thread(ThreadGroup group, Runnable target, String name, long stack size)
Thread Priority
Every thread has a thread priority and it will run according to the priority. I to 10 is the Range of thread priority in Java. Basically 10 is the highest priority, 1 is the lowest and 5 is the normal priority.
So to set the priority we have to invoke setPriority method to the thread.
Facts about the Thread Priority
- Most of the programmers think that 5 is the default priority for every threads but that is not the case. Lets say there are two threads T1(main) and T2(child) and the thread priority is set to 5 for both threads. In reality there will be no changes. There is actually a rule in Thread Priority which is Main thread’s default priority value s 5 because it was created by the system. thereafter any thread that are created will inherit the parent thread priority value. So when creating the T1, the priority will be 5 and once we create T2 from T1, it will also take the same value even we didn’t set anything. But later we can set the priority by invoking the
setPriority()
method to the particular thread. - What will happen when we give priority value which are not in the range like 11 then what will happen ?
I’ve tried to run a program by giving the thread priority to 11 and I got the output as follows,
Exception in thread "main" java.lang.IllegalArgumentException
at java.base/java.lang.Thread.setPriority(Thread.java:1137)
at threadSample.Application.main(Application.java:9)
as you can see I got an error saying IllegalArgumentException
. So there is no chance it will automatically set to 10.
- What will happen when we give priority value 1 and 10 for threads T1 and T2 respectively?
Most of the time there won’t be any big difference in the order of execution. Yes, the JVM will listen to the priority but we can’t be so sure that JVM will do accordingly. So if you want to see how it works, we have to implement this in the real project and there is way we can take the Thread dump and see.
Learn to code from industry experts! Enroll here
Join Method
Lets say there are two threads T1 and T2. T1 wants to wait for T2 to complete the task, then T1 should call the join method on T2 thread. We also can set time for T1 to wait. lets see what are those ways to call join method.
T2.join()
— this will wait forever or until T2 dies
T2.join(long millis)
—this will wait millis
milliseconds for this thread to die.
T2.join(long millis,int nanos)
— this will wait millis
milliseconds plus nanos
nanoseconds for this thread to die.
So whenever the join method is called, the thread will go to waiting state from Running state. In this example T1 thread will go to waiting state. Lets see on what case the T1 will go back to the running state,
- T2 complete its process
- Timeout (only if the time is set)
- When it is interrupted
Yield Method
When the yield()
method is invoked, then it will send a hint to the scheduler that the current thread is willing to yield its current use of a processor. It is a native method because it not implemented in Java. Lets say there are three threads T1,T2 and T3. So once the T1 calls the yield()
method, the scheduler will give chance to other threads and it is not sure that T2 or T3 will get the chance immediately. Lets say T2 is getting the chance and once it completes at that moment also we can’t say that the scheduler will give the chance to T1. Its totally depend on the process called Primitive Scheduling and if the platform doesn’t support this process, you won’t able to see these kind of execution.
Grab the opportunity to learn Java with Entri! Click Here
Sleep Method
When this method is called, it can wait for a certain amount of time. Here, there are two different approach to call this method such as,
sleep(long millis)
method which is a native method and simply we can give the sleep time in the parameter.sleep(long millis,int nanos)
method which is not a native method(implemented in Java).
So if the sleep time finishes or if there is any interruption then the thread will go back to the running state.
Interrupt Method
When this method is invoked, the particular thread will comeback to the ready state from the waiting state. That is why when calling a sleep method we should include try catch method as follows,
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
so to interrupt the thread we have to call the method as follows,
thread.interrupt();
In our example lets saythread
is sleeping for 5000 ms and once we call the above method it will come back to the ready state. Important note here is one interrupt will only work for one sleep method. What if we call this method on the thread
which is not sleeping. This will wait and execute the interrupt()
method once the sleep()
method is invoked until that it won’t do anything.