- What is Java?
- History of Java
- Hello Java Program
- Features of Java
- Basic Syntax
- Java Setup
- Data Types in Java
- Java Variables
- Operators in Java
- Java If-else Statement
- Switch Case Statement
- Java Loops
- Do-While Loop
- Java While Loop
- Continue Statement
- Break Statement in Java
- Constructors in Java
- Oops Concept in Java
- Features of OOPs
- Exeception handeling
- Aggregation (HAS-A relationship) in Java
- Method Overriding in Java
- Method Overloading
- Java Static Keyword
- Java This Keyword
- Java Final Keyword
- Static Binding and Dynamic Binding
- Abstract class in Java
- Access Modifiers in Java
- Difference between abstract class and interface
- Interface in Java
- Garbage Collection in Java
- Java Package
- Serialization and Deserialization in Java
- Java Inner Classes
- Java Applets
- Multithreading in Java
- Thread Priorities in Java
- Thread Creation
- Inter Thread Communication
- Wrapper Classes in Java
- Java Input Output
- Java AWT Introduction
- Java Layout Manager
- Java Layout Policy
- Java AWT Events
- Collection Framework
- Collection Framework List Interface
- Swing in Java
- Swing Utility Classes
- Swing Layout Managers
- Java JDBC
A Multithreading program contains two or more parts that can run concurrently.
A thread is a single flow of control within a program. Thread is very much similar to a process. The thread is also called a light-weight process.
Thread v/s Process.
Usually, different processes occupy different memory space. When the CPU shifts from one process to another, the state of the currently running process is saved, and another process is restored. No useful work is being done during state switch. The context switch time should be as less as possible to maximize the CPU utilization.
Threads are also like independent processes, but they share the same memory and state. The separate threads also have a separate state but the state is very small as compared to process state. The state may contain just program counter and stack pointer. So switching from one thread to another thread takes very little time. Thus the context switch time for threads is very small as compared to the process. Hence CPU utilization is high multiple threads compared to the utilization in case of multiple processes.
A multi-threaded program contains two or more parts that can run concurrently. Each part of such a program is called a thread, and each thread defines a separate path of execution. Thus, multi-threading is a specialized form of multi-tasking.
For example, a program may have three threads:
- One handling the printing.
- One handling the editing.
- One downloading a file from the Internet.
All these threads might be running concurrently thus maximizing the CPU utilization.
Most of the operating systems allow us to run two or more programs at the same time. It is referred to as process-bases multi-tasking. For example, we can run a Java program while we may be editing a word document. The process-based multitasking ensures that some program will be executed most of the time to increase CPU utilization.
In process-based multitasking, a program is the smallest unit of code that can be dispatched by the scheduler.
Thread is the smallest unit of execution in a thread-based multi-tasking environment. A process can be divided into a number of threads executing concurrently. This allows us to handle more than one task concurrently in a single program.
For example, we can edit a word document and at the same time print another document. Thread-based multitasking improves CPU utilization just like process-based multitasking. But at the same time it effectively speeds up the execution of a single program by executing its different parts concurrently in separate threads.
Thus process-based multitasking deals with the “big picture”, and thread-based multitasking handles the details.
The Java Thread Model:
The Java run-time system depends on threads for many things, and all the class libraries are designed with multi-threading in mind. Java uses threads to enable the entire environment to be asynchronous. This helps reduce inefficiency by preventing the waste of CPU cycles.
Single-threaded systems use an approach called an event loop with polling. In this model, a single thread of control runs in an infinite loop, polling a single event queue to decide what to do next. In a single-threaded environment, when a thread block (that is, suspends execution) because it is waiting for some resource, the entire program stops running.
The benefit of Java’s multi-threading is that the main loop/polling mechanism is eliminated. When a thread blocks in Java program, only the single thread that is blocked pauses, all other threads continue to run.
Thread Life Cycle (Thread States):
Thread exists in several states. A thread can be running. It can be ready to run as soon as it gets CPU time. A running thread can be suspended, which temporarily suspends its activity. A suspended thread can then be resumed, allowing it to pick up where it left off. A thread can be blocked when waiting for a resource. At any time, a thread can be terminated, which halts its execution immediately. Once terminated a thread cannot be resumed.
When we create a thread object, the thread is born and is in the newborn state. The thread is not yet scheduled for running.
At this stage, we can do only one of the following things with it:
Schedule it for running using start() method.
Kill it using stop( ) method.
If scheduled, it moves to runnable state. If we attempt to use any other method at this state, an exception will be thrown.
The runnable state means that the thread is ready for execution and is waiting for the processor’s availability. That is, the thread has joined the queue of threads that are waiting for execution. If all threads are of equal priority, they are given time slots to execute round-robin fashion.
The thread that relinquishes control joins the queue at the end and again waits for its run. However, if we want a thread to relinquish control to another thread of equal priority before its turn comes, it can do so by invoking the yield() method.
Running means that the processor has given its time to the thread for its execution. A running thread may relinquish its control in one of the following situations:
- Its time-slice is over.
- A higher priority thread pre-empts it.
- It yields, i.e. voluntarily relinquishes control.
- It has completed its execution.
- Some other thread stops it.
- It has been suspended using suspend() method. A suspended thread can be revived by using the resume() method. This approach is useful when we want to suspend a thread for some time due to certain reason, but do not want to kill it.
- It has been told to wait until some event occurs. This is done using the wait() method. The thread can be scheduled to run again using the notify() method.
- It is performing some I/O operation.
A thread is blocked when it is prevented from entering into the runnable state and subsequently the running form. This happens when the thread is suspended, sleeping or waiting to satisfy certain requirements. A blocked thread is considered “not runnable” but not dead and therefore fully qualified to run again.
Every thread has a life cycle. A running thread ends its life when it has completed executing its run() method. It has a natural death. However, we kill it by sending the stop message to it at any state, thus causing premature death. A thread can be killed as soon as it is born, or while it is running, or even when it is in “not runnable” (blocked condition).