Literature Review
Multi-threading means multiple flow of control. Multi-threading programming is a conceptual paradigm for programming where one can divide a program into two or more processes which can be run in parallel. There are two main advantages of multi-threading : Fist, program with multiple threads will, in general, result in better utilization of system resources, including the CPU, because another line of execution can grab the CPU when one line of execution is blocked. Second, there are several problems better solved by multiple threads. For example, we can easily write a multi-threaded program to show animation, play music, display documents, and down load files from the network at the same time.
Java is a multi-threaded language. Java allows to write a program where more than one processes can be executed concurrently within the single program. Java’s threads are often referred to as light weight threads, which means that they run in the same memory space. Because Java threads run in the same memory space, they can easily communicate among themselves because an object in one thread can call a method in another thread without any overhead from the operating system. In this Tutorial we will learn how to do multi-threaded programming in Java.
Basics of a thread
As with the Java concepts, everything about thread are defined in a class Thread. The Thread class encapsulates all of the control one will need over threads. The Thread class is our only link to manage how threads behave. In this Section, we will learn about : how to create and run a thread, the life cycle of a thread, and the thread controlling methods.
CHAPTER 6 –Threads and Multithreading in Java
In a networked world, it is common practice to share resources among multiple users. Therefore application programs designed to be deployed in a network should be designed to serve multiple users requests simultaneously. Even on desktop computers, users typically run multiple applications and carry out some operations in the background (e.g., printing) and some in the foreground (e.g., editing) simultaneously. With the increasing popularity of multicore processors, it is common to see even desktop and laptop computers with an ability to carry out multiple tasks concurrently. To meet these requirements, modern programming languages and operating systems are designed to support the development of applications containing multiple activities that can be executed concurrently. Modern operating systems hold more than one activity (program) in memory and the processor can switch among all to execute them. This simultaneous occurrence of several activities on a computer is 14 Multithreaded Programming 365 known as multitasking. For example, you can open a fi le using MS Word and you can work on MS Access for creating your database. Two applications, MS Word and MS Access, are available in memory and the processor (by means of the operating system) switches to the application you are actively working on.
Here two different applications are made to run concurrently by the same processor. The operating system supports multitasking in a cooperative or preemptive manner. In cooperative multitasking each application is responsible for relinquishing control to the processor to enable it to execute the other application. Earlier versions of operating systems followed cooperative multitasking. Modern operating systems such as Windows 95, Windows 98, Windows NT, and Windows 2000 support preemptive multitasking. In the preemptive type multitasking, the processor is responsible for executing each application in a certain amount of time called a timeslice. The processor then switches to the other applications, giving each its timeslice. The programmer is relieved from the burden of relinquishing control from one application to another.
The operating system takes care of it. A single processor computer is shared among multiple applications with preemptive multitasking. Since the processor is switching between the applications at intervals of milliseconds, you feel that all applications run concurrently. Actually, this is not so. To have true multitasking, the applications must be run on a machine with multiple processors. Multitasking results in effective and simultaneous utilization of various system resources such as processors, disks, and printers.
As multitasking is managed by operating systems, we encourage readers to refer to books related to that topic. In this chapter, we focus on learning how to write an application containing multiple tasks (i.e., objects containing operations to be performed) that can be executed concurrently. In Java, this is realized by using multithreading techniques
The life cycle of threads in Java is very similar to the life cycle of processes running in an operating system. During its life cycle the thread moves from one state to another depending on the operation performed by it or performed
Java thread can be in one of the following states:
∑ NEW A thread that is just instantiated is in new state. When a start() method is invoked, the thread moves to the ready state from which it is automatically moved to runnable state by the thread scheduler.
∑ RUNNABLE (readyrunning) A thread executing in the JVM is in running state.
∑ BLOCKED A thread that is blocked waiting for a monitor lock is in this state. This can also occur when a thread performs an I/O operation and moves to next (runnable) state. ∑ WAITING A thread that is waiting indefinitely for another thread to perform a particular action is in this state.
∑ TIMED_WAITING (sleeping) A thread that is waiting for another thread to perform an action for up to a specified waiting time is in this state.
The Java language includes a powerful threading facility built into the language. You can use the threading facility to:
• Increase the responsiveness of GUI applications
• Take advantage of multiprocessor systems
• Simplify program logic when there are multiple independent entities
• Perform blocking I/O without blocking the entire program
Importance of understanding the life cycle of Thread in Java and its states
The thread life cycle in Java is an important concept in multithreaded applications. Let’s see the importance of understanding the life cycle of a thread in Java:
- Understanding a thread’s life cycle and states in Java is essential because it helps identify potential issues that can arise when creating or manipulating threads.
- It allows developers to utilize resources more effectively and prevent errors related to multiple threads accessing shared data simultaneously.
- Knowing the thread states in Java helps predict a program’s behaviour and debug any issues that may arise.
- It also guides the developer on properly suspending, resuming, and stopping a thread as required for a specific task.
The Life Cycle of Thread in Java – Thread State
In Java, the life cycle of Thread goes through various states. These states represent different stages of execution. Here are examples of each stage of the life cycle of Thread in Java with real-life use cases:
1. New (born) state
- Example: Creating a new thread using the Thread class constructor.
- Use case: Creating a new thread to perform a background task while the main Thread continues with other operations
2. Runnable state
- Example: After calling the start() method on a thread, it enters the runnable state.
- Use case: Multiple threads competing for CPU time to perform their tasks concurrently.
3. Running state
- Example: When a thread executes its code inside the run() method.
- Use case: A thread executing a complex computation or performing a time-consuming task.
4. Blocked state:
- Example: When a thread tries to access a synchronized block or method, but another thread already holds the lock.
- Use case: Multiple threads accessing a shared resource can only be obtained by a single Thread, such as a database or a file.
Transitions Between Thread States
Threads in a multithreaded environment can transition between different thread states in Java as they execute. The Java Thread class defines these states and represents different stages in the lifecycle of a thread. The possible states include:
- New: When a thread has just been created, it is in the “New” state. At this point, the Thread is not yet scheduled for execution and has not started running.
- Runnable: A thread enters the “Runnable” state after invoking the start() method. In this state, the Thread is eligible to be scheduled by the operating system and can start executing its code.
- Blocked/Waiting: A thread can enter the “Blocked” or “Waiting” state under certain circumstances. For example, if a thread is waiting for a lock to be released by another thread, it goes into the “Blocked” state. Similarly, if a thread waits for a specific condition to be satisfied, it enters the “Waiting” state. In these states, the Thread is not actively executing its code and is not eligible for scheduling.
- Timed Waiting: Threads can also enter the “Timed Waiting” state, similar to the “Waiting” state but with a time constraint. For instance, a thread can enter the “Timed Waiting” state when it calls methods like Thread.sleep() or Object.wait() with a specific timeout value. The Thread remains in this specific state until the timeout expires or until it receives a notification from another thread.
- Terminated: The final state in the thread lifecycle is the “Terminated” state. A thread enters this state when it completes its execution or when an unhandled exception occurs within the Thread. Once a thread is terminated, it cannot transition to any other state.
References :