An operating system process can have multiple threads. Multiple threads allow the process to do tasks concurrently. Even better, if there are multiple processors, then these threads can run on different multiple processors, and thereby, reach (almost) true parallelism. Hence, an application with tasks that can be done independently, or with little (bounded) dependency on each other, can greatly benefit from using threads.
Let us consider an example of a web-server that handles multiple HTTP requests. The web-server can spawn multiple threads and each thread can handle a single request. At the same time, another thread can listen for incoming HTTP requests. Thus, threads can enable a web-server to not only listen for incoming requests, but also to process existing requests -- and all of these happen concurrently.
Threads belonging to a process share the address space, file descriptors, etc belonging to the parent process with each other. However, each thread does maintain its own stack so that it can execute common lines of code independently of other threads. Since threads do not have to maintain their own address space etc, they are also referred to as light weight processes!
One naive approach may be to run concurrent tasks as multiple processes. But, switching between different processes (aka scheduling) has a lot more overhead than switching between threads within one process. No less important, communication between different processes would require some form of inter process communication (IPC) which again has a lot more overhead, not to mention more complicated. By comparison, communication between threads is relatively simpler since they share the address space, file descriptors belonging to the parent process.
Of course, when we have multiple threads working together, there is always a risk of them overwriting any common memory location (or critical data). Therefore, isolating the critical data in the memory and making threads access them in a synchronized manner goes hand in hand with creating threads. The good news is that Java has a really good built in support for multi threaded programming.
"Thread Class" in Java offers all the required support, in order to accomplish the task of writing multi-threaded programming. There are 2 ways of creating a thread in Java. First, implement the Runnable interface. Second, extend the thread class itself. Let us look into a sample program and understand the concepts of multi-threading in Java.
Here are the concepts that are covered in the below sample program. It is recommended to read these concepts in tandem with the below sample program for better/clearer understanding.
1. "sampleThread implements Runnable" : The class that creates new thread/threads needs to implement the interface "Runnable". To implement runnable, a class needs to implement "public void run()" method. In the below example program, "sampleThread" class satisfies both the conditions. 2. "Thread thread" : A new thread is created by instantiating and object of class "Thread". "Thread" class provides a lot of methods which will be used while writing a multi thread programming in Java. We can see in the below example, we have used the methods like sleep, start etc. 3. sampleThread extends Thread : Since "Thread" class has all the required methods to write a multi threaded programming in Java, a class can create new threads by extending the "Thread" class. Thus, the "Thread" class is a super class and any class that extends "Thread" class need to override the "public void run" method. This is an other way of creating multiple threads in Java (First being implements Runnable interface). 4. "thread = new Thread(this, threadName);" : A new thread is created. Notice the parameterized constructor called in the below program. Thread class provides quite a few versions of constructors and the one used below takes "this" and "Thread name" as the arguments. the argument "this", implies the object of the class that implements the Runnable interface. 5. "public void run()" : This is method that needs to be implemented (Override in the case of "Extends Thread" approach ) by the class that implements Runnable interface. This method is the entry point for all the child threads that are created. 6. "thread.start();" : This is the method that starts the thread, which in turn starts the execution of thread starting with "run() method". Thread execution does not begin with out this statement. 7. "Thread.sleep(2000);" : "sleep" is an other method available in "Thread" class. This will let the thread to sleep for "n" Milli seconds. In other words, the execution of a thread is paused, for the amount of time passed as an argument to this method. This method might throw an exception, so it is required that we write a try/catch block around it. 8. "skyfallThread.thread.isAlive()" : Usually any program will have a main thread and any number of child threads. In many cases, it is not desirable to allow main thread to finish execution before its child threads do. This methods when called returns "true" if the thread that is called up on is still running, "false" other wise. This method helps the "main" thread to understand the state of his child threads. 9. "skyfallThread.thread.join()" : While the "isAlive()" method is useful, there is another better way for learning about the child/other threads. The "join" method will wait for the termination of the thread that is called up on, in the below example Main thread will wait for the termination of "skyfallThread and CasinoRoyalThread". "join" method will ensure Main method is terminated only after all its child threads are finished with their execution. There could be a case, you would want to wait only for a definite amount of time, so there is an other version of join method that take time as an argument, which determines the wait time. 10. Thread priority : Thread priority is used by the scheduler in allocating the CPU time. Java provides different levels of priority (1 - 10). While, MIN_PRIORITY is 1, the MAX_PRIORITY is 10, and the default priority of any thread is set to NORM_PRIORITY which is 5. ("CasinoRoyalThread.thread.getPriority()")The methods getPriority and setPriority() are used in setting and getting the priorities of a thread.
Let us look at an example to understand the concept of multi-threading in Java.
class sampleThread implements Runnable { Thread thread; sampleThread(String threadName) { System.out.println(" Creating Thread, " + threadName); thread = new Thread(this, threadName); thread.setName(threadName); if (threadName == "Skyfall") { thread.setPriority(Thread.NORM_PRIORITY + 2); } thread.start(); } @Override public void run() { System.out.println (" Entry point to the thread, " + thread.getName()); try { Thread.sleep(2000); } catch (InterruptedException e) { System.out.println (" Exception Caught" + e); } System.out.println(" Exiting the RUN method, Thread " + thread.getName()); } } public class multiThreadingExample { public static void main(String[] args) { System.out.println(" Main Thread Starts.... "); sampleThread skyfallThread = new sampleThread("Skyfall"); sampleThread CasinoRoyalThread = new sampleThread("Casino Royal"); System.out.println (" Casino Royal Thread (Default) Priority " + CasinoRoyalThread.thread.getPriority()); System.out.println (" Sky Fall Thread ( Set ) Priority " + skyfallThread.thread.getPriority()); System.out.println (" Main thread waiting...."); System.out.println (" Casino Royal Thread, alive ? :" + CasinoRoyalThread.thread.isAlive()); while (skyfallThread.thread.isAlive()) { System.out.print(" Sky fall Thread still alive, "); System.out.println ("Main thread waiting...."); try { Thread.sleep(400); } catch (InterruptedException e) { System.out.println (" Exception Caught" + e); } } // Wait for the child threads to finish execution. try { skyfallThread.thread.join(); CasinoRoyalThread.thread.join(); } catch (InterruptedException e) { System.out.println (" Exception caught " + e); } System.out.println(" Main Thread Exits "); } }
The above sample program does not have any meaning full meaning, it just illustrates some of the basic concepts of threading in Java. This program creates 2 threads "skyfallThread" and " CasinoRoyalThread", and shows the execution flow of the threads using some println statements. Here is the output.
Main Thread Starts.... Creating Thread, Skyfall Creating Thread, Casino Royal Entry point to the thread, Skyfall Entry point to the thread, Casino Royal Casino Royal Thread (Default) Priority 5 Sky Fall Thread ( Set ) Priority 7 Main thread waiting.... Casino Royal Thread, alive ? :true Sky fall Thread still alive, Main thread waiting.... Sky fall Thread still alive, Main thread waiting.... Sky fall Thread still alive, Main thread waiting.... Sky fall Thread still alive, Main thread waiting.... Sky fall Thread still alive, Main thread waiting.... Exiting the RUN method, Thread Skyfall Exiting the RUN method, Thread Casino Royal Main Thread Exits