A thread is the most important part of concurrent execution. Threads are sometimes referred to as lightweight processes. Like processes, threads are independent, concurrent paths of execution through a program, and each thread has its own stack, its own program counter, and its own local variables. However, threads within a process are less insulated from each other than separate processes are. They share memory, file handles, and another per-process state.
Threading is a facility to allow multiple activities to coexist within a single process. Most modern operating systems support threads and the concept of threads has been around in various forms for many years. Java is the first mainstream programming language to explicitly include threading within the language itself, rather than treating threading as a facility of the underlying operating system.
Every Java program has at least one thread - the main thread. When a Java program starts, the JVM creates the main thread and calls the program's main() method within that thread.
Importance of main thread
Because this thread affects the other 'child' threads
Because it performs various shutdown actions
It is created automatically when your program is started.
The Java run-time system depends on threads for many things. Threads reduce inefficiency by preventing the waste of CPU cycles.
Threads exist in several states. Such as:
New - When we create an instance of Thread class, a thread is in a new state.
Suspended - 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.
Blocked - A java thread can be blocked when waiting for a resource.
Running - The Java thread is in running state.
Terminated - A thread can be terminated, which halts its execution immediately at any given time. Once a thread is terminated, it cannot be resumed.
Java provides built-in support for multithreading. Multithreading in Java contains two or more parts that can run concurrently. A Java thread is actually a lightweight process. Each part of such a program is called a thread and each thread defines a separate path of the execution. Thus, multithreading is a specialized form of multitasking.
Java's creators have graciously designed two ways of creating threads:
Extending a class is the way Java inherits methods and variables from a parent class. In this case, one can only extend or inherit from a single parent class. This limitation within Java can be overcome by implementing interfaces, which is the most common way to create threads. The act of inheriting merely allows the class to be run as a thread. It is up to the class to start() execution, etc.
Interfaces provide a way for programmers to lay the groundwork of a class. They are used to design the requirements for a set of classes to implement. The interface sets everything up, and the class or classes that implement the interface do all the work. The different set of classes that implement the interface have to follow the same rules. The easiest way to create a thread is to create a class that implements the Runnable interface. To implement the Runnable interface, a class need only implement a single method called run( ).
How do threads work?
A thread is essentially a subdivision of a process, or "lightweight process" (LWP) on some systems. A process is generally the most major and separate unit of execution recognized by the OS.
The typical relationship between processes, threads and various other elements of the OS are shown in Figure 1 opposite. This shows two processes, each split into two threads (a simplistic situation, of course: there will be typically dozens of processes, some with dozens or more threads).
Each process has its own memory space. When Process 1 accesses some given memory location, say 0x8000, that address will be mapped to some physical memory address1. But from Process 2, location 0x8000 will generally refer to a completely different portion of physical memory.
A thread is a subdivision that shares the memory space of its parent process. So when either Thread 1 or Thread 2 of Process 1 accesses "memory address 0x8000", they will be referring to the same physical address.
Threads belonging to a process usually share a few other key resources as well, such as their working directory, environment variables, file handles etc.
On the other hand, each thread has its own private stack and registers, including program counter. These are essentially the things that threads need in order to be independent.
Depending on the OS, threads may have some other private resources too, such as thread-local storage (effectively, a way of referring to "variable number X", where each thread has its own private value of X).
The OS will generally attach a bit of "housekeeping" information to each thread, such as its priority and state (running, waiting for I/O etc).
So, why use threads?
There are many reasons to use threads in your Java programs. Some of the reasons for using threads are:
Make the UI more responsive
Take full advantage of multiprocessor systems
Perform asynchronous or background processing
To make a task run parallel to another task
For reducing response time
To sever multiple clients at the same time
Stock photo from fatmawati achmad zaenuri