Thread Concept in Java
Before introducing the thread concept, we were unable to run more than one task in parallel. It was a drawback, and to remove that drawback, Thread Concept was introduced.
A Thread is a very light-weighted process, or we can say the smallest part of the process that allows a program to operate more efficiently by running multiple tasks simultaneously.
In order to perform complicated tasks in the background, we used the Thread concept in Java. All the tasks are executed without affecting the main program. In a program or process, all the threads have their own separate path for execution, so each thread of a process is independent.
Another benefit of using thread is that if a thread gets an exception or an error at the time of its execution, it doesn’t affect the execution of the other threads. All the threads share a common memory and have their own stack, local variables and program counter. When multiple threads are executed in parallel at the same time, this process is known as Multithreading.
In a simple way, a Thread is a:
- Feature through which we can perform multiple activities within a single process.
- Lightweight process.
- Series of executed statements.
- Nested sequence of method calls.
Thread Model
Just like a process, a thread exists in several states. These states are as follows:
Thread Concept in Java
1) New (Ready to run)
A thread is in New when it gets CPU time.
2) Running
A thread is in a Running state when it is under execution.
3) Suspended
A thread is in the Suspended state when it is temporarily inactive or under execution.
4) Blocked
A thread is in the Blocked state when it is waiting for resources.
5) Terminated
A thread comes in this state when at any given time, it halts its execution immediately.
Thread priorities
Java assigns to each thread a priority that determines how that thread should be treated with respect to the others. Thread priorities are integers that specify the relative priority of one thread to another. As an absolute value, a priority is meaningless; a higher-priority thread doesn’t run any faster than a lower-priority thread if it is the only thread running. Instead, a thread’s priority is used to decide when to switch from one running thread to the next. This is called a context switch.
The rules that determine when a context switch takes place are simple:
- A thread can voluntarily relinquish control. This is done by explicitly yielding, sleeping, or blocking on pending I/O. In this scenario, all other threads are examined, and the highest-priority thread that is ready to run is given the CPU.
- A thread can be preempted by a higher-priority thread. In this case, a lower priority thread that does not yield the processor is simply preempted. Basically, as soon as a higher priority thread wants to run, it does. This is called preemptive multitasking.
In cases where two threads with the same priority are competing for CPU cycles, the situation is a bit complicated. For operating systems such as Windows 98, threads of equal priority are time-sliced automatically in round-robin fashion. For other types of operating systems, threads of equal priority must voluntarily yield control to their peers. If they don’t, the other threads will not run.
Synchronization
Because multithreading introduces an asynchronous behaviour to the programs, there must be a way to enforce synchronicity whenever we need it. For example, if we want two threads to communicate and share a complicated data structure, such as a linked list, you need some way to ensure that they don’t conflict with each other. That’s, one must prevent one thread from writing data while another thread is in the middle of reading it. For this purpose, Java implements an elegant twist on an age-old model of interprocess synchronization: the monitor. The monitor is a control mechanism first defined by C.A.R. Hoare. One can think of a monitor as a very small box that can hold only one thread. Once a thread enters a monitor, all other threads must wait until that thread exits the monitor. In this way, a monitor can be used to protect a shared asset from being manipulated by more than one thread at a time.
Messaging
After we divide the program into separate threads, we need to define how they will communicate with each other. When programming with most other languages, one must depend on the operating system to establish communication between threads. This, of course, adds overhead. By contrast, Java provides a clean, low-cost way for two or more threads to talk to each other, via calls to predefined methods that all objects have. Java’s messaging system allows a thread to enter a synchronized method on an object, and then wait there until some other thread explicitly notifies it to come out.
Thread class and Runnable interface
The Thread Class and the Runnable Interface Java’s multithreading system is built upon the Thread class, its methods, and its companion interface, Runnable. Thread encapsulates a thread of execution. Since we can’t directly refer to the ethereal state of a running thread, we deal with it through its proxy, the Thread instance that spawned it. To create a new thread, The program will either extend Thread or implement the Runnable interface. The Thread class defines several methods that help manage threads.
• getName()
This method returns the name of the thread. The return type of this method is String. The general form of this method is:
Syntax:
public final String getName()
• getPriority()
This method returns the priority of a thread. It returns priority in the form of an integer value ranging from 1 to 10. The maximum priority is 10, the minimum priority is 1, and normal priority is 5.
Syntax:
public final int getPriority() // Return type is an integer.
• run()
The run() method moves the thread into running state. It is executed only after the start() method has been executed. The general syntax is as
follows:
Syntax:
public void run()
• start()
The start() method is used to start the execution of a thread by calling its run() method. JVM calls the run() method on the thread. The general
syntax for start() method is as follows:
Syntax:
public void start()
• isAlive()
This method is used to check the thread is alive or not. It returns a boolean value (true or false) that indicates thread is running or not. The isAlive() method is final and native. The general syntax for isAlive() method is as follows:
Syntax:
public final native boolean isAlive()
• join()
The join() method is used to make a thread wait for another thread to terminate its process. The general syntax is
Syntax:
public final void join() throw InterruptedException
• sleep()
The sleep() method puts currently executing thread to sleep for specified number of milliseconds. This method is used to pause the current thread for specified amount of time in milliseconds.Since this method is static, so we can access it through Thread class name. The general syntax of this method is as follows:
Syntax:
public static void sleep(long milliseconds) throws Interrupted Exception
Main thread in Java
Java provides built-in support for multithreaded programming. 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.
Main Thread
When a Java program starts up, one thread begins running immediately. This is usually called the main thread of our program, because it is the one that is executed when our program begins.
Properties:
- It is the thread from which other “child” threads will be spawned.
- Often, it must be the last thread to finish execution because it performs various shutdown actions.
Flow diagram:
How to control Main thread?
The main thread is created automatically when our program is started. To control it we must obtain a reference to it. This can be done by calling the method currentThread( ) which is present in Thread class. This method returns a reference to the thread on which it is called. The default priority of Main thread is 5 and for all remaining user threads priority will be inherited from parent to child.
// Java program to control the Main Thread
public class Test extends Thread
{
public static void main(String[] args)
{
// getting reference to Main thread
Thread t = Thread.currentThread();
// getting name of Main thread
System.out.println(“Current thread: ” + t.getName());
// changing the name of Main thread
t.setName(“Geeks”);
System.out.println(“After name change: ” + t.getName());
// getting priority of Main thread
System.out.println(“Main thread priority: “+ t.getPriority());
// setting priority of Main thread to MAX(10)
t.setPriority(MAX_PRIORITY);
System.out.println(“Main thread new priority: “+ t.getPriority());
for (int i = 0; i < 5; i++)
{
System.out.println(“Main thread”);
}
// Main thread creating a child thread
ChildThread ct = new ChildThread();
// getting priority of child thread
// which will be inherited from Main thread
// as it is created by Main thread
System.out.println(“Child thread priority: “+ ct.getPriority());
// setting priority of Main thread to MIN(1)
ct.setPriority(MIN_PRIORITY);
System.out.println(“Child thread new priority: “+ ct.getPriority());
// starting child thread
ct.start();
}
}
// Child Thread class
class ChildThread extends Thread
{
@Override
public void run()
{
for (int i = 0; i < 5; i++)
{
System.out.println(“Child thread”);
}
}
}
Output:
Current thread: main
After name change: Geeks
Main thread priority: 5
Main thread new priority: 10
Main thread
Main thread
Main thread
Main thread
Main thread
Child thread priority: 10
Child thread new priority: 1
Child thread
Child thread
Child thread
Child thread
Child thread
Create a Thread
There are two ways to create a thread:
- By extending Thread class
- By implementing Runnable interface.
Thread class:
Thread class provide constructors and methods to create and perform operations on a thread. Thread class extends Object class and implements Runnable interface.
Commonly used Constructors of Thread class:
Thread()
Thread(String name)
Thread(Runnable r)
Thread(Runnable r, String name)
Commonly used methods of Thread class:
public void run(): is used to perform action for a thread.
public void start(): starts the execution of the thread. JVM calls the run() method on the thread.
public void sleep(long miliseconds): Causes the currently executing thread to sleep (temporarily cease execution) for the specified number of milliseconds.
public void join(): waits for a thread to die.
public void join(long miliseconds): waits for a thread to die for the specified miliseconds.
public int getPriority(): returns the priority of the thread.
public int setPriority(int priority): changes the priority of the thread.
public String getName(): returns the name of the thread.
public void setName(String name): changes the name of the thread.
public Thread currentThread(): returns the reference of currently executing thread.
public int getId(): returns the id of the thread.
public Thread.State getState(): returns the state of the thread.
public boolean isAlive(): tests if the thread is alive.
public void yield(): causes the currently executing thread object to temporarily pause and allow other threads to execute.
public void suspend(): is used to suspend the thread(depricated).
public void resume(): is used to resume the suspended thread(depricated).
public void stop(): is used to stop the thread(depricated).
public boolean isDaemon(): tests if the thread is a daemon thread.
public void setDaemon(boolean b): marks the thread as daemon or user thread.
public void interrupt(): interrupts the thread.
public boolean isInterrupted(): tests if the thread has been interrupted.
public static boolean interrupted(): tests if the current thread has been interrupted.
Runnable interface:
The Runnable interface should be implemented by any class whose instances are intended to be executed by a thread. Runnable interface have only one method named run().
public void run(): is used to perform action for a thread.
Starting a thread:
The start() method of Thread class is used to start a newly created thread. It performs the following tasks:
A new thread starts(with new callstack).
The thread moves from New state to the Runnable state.
When the thread gets a chance to execute, its target run() method will run.
1) Java Thread Example by extending Thread class
FileName: Multi.java
class Multi extends Thread {
public void run() {
System.out.println(“thread is running…”);
}
public static void main(String args[]) {
Multi t1 = new Multi();
t1.start();
}
}
Output:
thread is running…
2) Java Thread Example by implementing Runnable interface
FileName: Multi3.java
class Multi3 implements Runnable {
public void run() {
System.out.println(“thread is running…”);
}
public static void main(String args[]) {
Multi3 m1 = new Multi3();
Thread t1 = new Thread(m1); // Using the constructor Thread(Runnable r)
t1.start();
}
}
Output:
thread is running…
If you are not extending the Thread class, your class object would not be treated as a thread object. So you need to explicitly create the Thread class object. We are passing the object of your class that implements Runnable so that your class run() method may execute.
3) Using the Thread Class: Thread(String Name)
We can directly use the Thread class to spawn new threads using the constructors defined above.
FileName: MyThread1.java
public class MyThread1 {
// Main method
public static void main(String argvs[]) {
// creating an object of the Thread class using the constructor Thread(String
// name)
Thread t = new Thread(“My first thread”);
// the start() method moves the thread to the active state
t.start();
// getting the thread name by invoking the getName() method
String str = t.getName();
System.out.println(str);
}
}
Output:
My first thread
4) Using the Thread Class: Thread(Runnable r, String name)
FileName: MyThread2.java
public class MyThread2 implements Runnable {
public void run() {
System.out.println(“Now the thread is running …”);
}
// main method
public static void main(String argvs[]) {
// creating an object of the class MyThread2
Runnable r1 = new MyThread2();
// creating an object of the class Thread using Thread(Runnable r, String name)
Thread th1 = new Thread(r1, “My new thread”);
// the start() method moves the thread to the active state
th1.start();
// getting the thread name by invoking the getName() method
String str = th1.getName();
System.out.println(str);
}
}
Output:
My new thread
Now the thread is running …
Multithreading in Java
Multithreading in Java is a process of executing multiple threads simultaneously.
A thread is a lightweight sub-process, the smallest unit of processing. Multiprocessing and multithreading, both are used to achieve multitasking.
However, we use multithreading than multiprocessing because threads use a shared memory area. They don’t allocate separate memory area so saves memory, and context-switching between the threads takes less time than process.
Java Multithreading is mostly used in games, animation, etc.
Advantages of Java Multithreading
- It doesn’t block the user because threads are independent and you can perform multiple operations at the same time
- You can perform many operations together, so it saves time.
- Threads are independent, so it doesn’t affect other threads if an exception occurs in a single thread.
Creating Multiple Threads
When we are using multiple threads in our application, we’ll create the threads and call the start() method on these threads. It’s the Java Virtual Machine that calls the run method of this thread when the resources and CPU are ready. Then the thread will execute the run() method and later transition to terminated state.
Suppose you have a scenario where you want to start further processing only when a thread has ended then how will you know that a thread has ended?
Java multi-threading provides two ways to find that–
- isAlive()
- join()
Java Thread isAlive() method
The isAlive() method of thread class tests if the thread is alive. A thread is considered alive when the start() method of thread class has been called and the thread is not yet dead. This method returns true if the thread is still running and not finished.
Syntax:
public final boolean isAlive()
Return
This method will return true if the thread is alive otherwise returns false.
Example
public class JavaIsAliveExp extends Thread
{
public void run()
{
try
{
Thread.sleep(300);
System.out.println(“is run() method isAlive “+Thread.currentThread().isAlive());
}
catch (InterruptedException ie) {
}
}
public static void main(String[] args)
{
JavaIsAliveExp t1 = new JavaIsAliveExp();
System.out.println(“before starting thread isAlive: “+t1.isAlive());
t1.start();
System.out.println(“after starting thread isAlive: “+t1.isAlive());
}
}
Output:
before starting thread isAlive: false
after starting thread isAlive: true
is run() method isAlive true
Java Thread join() method
The join() method of thread class waits for a thread to die. It is used when you want one thread to wait for completion of another. This process is like a relay race where the second runner waits until the first runner comes and hand over the flag to him.
Syntax
public final void join()throws InterruptedException
public void join(long millis)throwsInterruptedException
public final void join(long millis, int nanos)throws InterruptedException
Parameter
millis: It defines the time to wait in milliseconds
nanos: 0-999999 additional nanoseconds to wait
Return
It does not return any value.
Exception
IllegalArgumentException: This exception throws if the value of millis is negative, or the value of nanos is not in the range 0-999999
InterruptedException: This exception throws if any thread has interrupted the current thread. The interrupted status of the current thread is cleared when this exception is thrown.
Example 1
public class JoinExample1 extends Thread
{
public void run()
{
for(int i=1; i<=4; i++)
{
try
{
Thread.sleep(500);
}catch(Exception e){System.out.println(e);}
System.out.println(i);
}
}
public static void main(String args[])
{
// creating three threads
JoinExample1 t1 = new JoinExample1();
JoinExample1 t2 = new JoinExample1();
JoinExample1 t3 = new JoinExample1();
// thread t1 starts
t1.start();
// starts second thread when first thread t1 is died.
try
{
t1.join();
}catch(Exception e){System.out.println(e);}
// start t2 and t3 thread
t2.start();
t3.start();
}
}
Output:
1 2 3 4 1 1 2 2 3 3 4 4
Synchronization in Java
Synchronization in Java is the capability to control the access of multiple threads to any shared resource.
Java Synchronization is better option where we want to allow only one thread to access the shared resource.
Why use Synchronization?
The synchronization is mainly used to
- To prevent thread interference.
- To prevent consistency problem.
Java Synchronized Method
If you declare any method as synchronized, it is known as synchronized method.
Synchronized method is used to lock an object for any shared resource.
When a thread invokes a synchronized method, it automatically acquires the lock for that object and releases it when the thread completes its task.
Example:
class Table {
synchronized void printTable(int n) {// synchronized method
for (int i = 1; i <= 5; i++) {
System.out.println(n * i);
try {
Thread.sleep(400);
} catch (Exception e) {
System.out.println(e);
}
}
}
}
class MyThread1 extends Thread {
Table t;
MyThread1(Table t) {
this.t = t;
}
public void run() {
t.printTable(5);
}
}
class MyThread2 extends Thread {
Table t;
MyThread2(Table t) {
this.t = t;
}
public void run() {
t.printTable(100);
}
}
public class TestSynchronization2 {
public static void main(String args[]) {
Table obj = new Table();// only one object
MyThread1 t1 = new MyThread1(obj);
MyThread2 t2 = new MyThread2(obj);
t1.start();
t2.start();
}
}
Output:
5
10
15
20
25
100
200
300
400
500
Synchronized Statement:
A synchronized Statement can only be executed once the thread has obtained a lock for the object or the class that has been referred to in the statement. Synchronized statement contains a synchronized block, within which is placed objects and methods that are to be synchronized.
Example:
public void run()
{
synchronized(p1)
{
//synchronize statement. P1 here is an object of some class P
p1.display(s1);
}
}
I believe this web site has very excellent indited content material blog posts.