We are familiar with the benefits of multi-tasking. The concurrency results in faster throughput. Java supports multithreaded programming. In a multithreaded program, two or more parts of a program can execute concurrently. Each part of such a multithreaded program is known as a thread. Each thread has its own path of execution. Hence, multithreading is a specialized form of multi-tasking.
We are limiting our discussion to threads in this lecture.
In a thread-based multitasking environment, the thread is the atom of code. It means that a single program can have two or more tasks concurrently. Multitasking threads require less overhead compared to multitasking processes. Processes are heavyweight tasks that require their own separate address spaces using PCB. Multithreading features writing efficient programs to utilize processing power at its maximum level.
Faster throughput as mentioned earlier is possible because the idle time of CPU is minimum possible in the multi-threaded environment. In a single-threaded environment, the program needs to wait for each of the tasks to complete before proceeding forward—despite most of the time the program is idle, waiting for input. In contrast, multithreading helps us reduce idle time as another thread is running regardless of other is in execution or waiting for the state.
The thread can be in any of the below-mentioned states:
State | Description |
---|---|
New | At the creation of a new thread |
Ready | Once it gets CPU time, the thread is ready |
Running | A ready thread turns to running |
Suspended | A running thread can get suspended |
Resumed | A suspended thread can be resumed |
Terminated | When a thread halts execution |
Java assigns an integral number to each of the threads. The purpose is to determine the relative priority of the thread compared to all the threads available. It helps in the process called a context switch. In simpler words, it helps to decide the priority of allotting CPU to a specific thread. As a result, a lesser priority thread is switched by the higher-priority thread.
Synchronization comes hand in hand with the multi-tasking environment. In order to solve the asynchronous behavior of the multi-threaded program, there has to be some ground to enforce synchronization. For this purpose, Java implements a variant of interprocess synchronization: the monitor. The monitor is a control mechanism first defined by C.A.R. Hoare. A monitor can be considered as a single-seater ride. One and only one thread can ride at a time. Once a thread is inside a synchronized method, no other thread can be into it making it synchronization compliant code.
Once a program is divided into one or more threads, it is obvious that there will be some information sharing between the threads. Java approaches messaging and information sharing with the help of JMS. Java’s messaging system allows a thread to enter a synchronized method of an object, and retain until it receives explicit notification from another thread to come out.
When a Java program starts, one thread that begins running immediately is the main thread of your program. It is called so because it is the first one that is executed when the program begins. It is an inevitable thread for the following reason:
Hence, all the examples discussed until now have used a single thread of execution.
Java’s multithreading system is built on the pillars of the Thread class and Runnable interface. To create a new thread, you can either extend
Thread or implement
the Runnable interface. Thread class encapsulates a thread of execution. It defines several methods that help manage threads. Referral to the ethereal state of a running thread cannot be done directly and is dealt with its proxy, the Thread instance that spawned it.
This was an overview of Java threads. We will discuss the life cycle of threads in the next lecture.