Multithreading and Generic Programming
Multithreading and Generic Programming
Multithreading and Generic Programming
As shown in the above figure, a thread is executed inside the process. There is context-switching
between the threads. There can be multiple processes inside the OS and one process can have
multiple threads.
Thread life cycle
A thread goes through various stages in its life cycle. For example, a thread is born, started, runs, and
then dies. A thread lies only in one of the shown states at any instant:
New
Runnable
Running
Non-Runnable (Blocked)
Terminated
1. New
When a new thread is created, it is in the new state. The thread has not yet started to run. The thread is in new
state if you create an instance of Thread class but before the invocation of start( ) method.
2. Runnable
The thread is in runnable state after invocation of start( ) method, but the thread scheduler has not selected it
to be the running thread. It is the duty of the thread scheduler to provide the thread time to run, i.e., moving
the thread the running state.
3. Running
The thread is in running state if the thread scheduler has selected it. When the thread gets the CPU, it moves
from the runnable to the running state
4. Non-Runnable (Blocked)
This is the state when the thread is still alive, but is currently not eligible to run.
5. Terminated
A thread is in terminated or dead state when its run( ) method exits. A thread reaches the termination state
because of the following reasons:
When a thread has finished its job, then it exists or terminates normally.
Abnormal termination: It occurs when some unusual events such as an unhandled exception or
segmentation fault.
A terminated thread means the thread is no more in the system. In other words, the thread is dead, and there is
no way one can respawn (active after kill) the dead thread.
Thread Class and Runnable Interface
Java’s multithreading system is built upon the Thread class, its methods, and its companion
interface, Runnable. To create a new thread, program will either
extend Thread or implement the Runnable interface.
The Thread class defines several methods that help manage threads. The table below displays the
same:
Method Meaning
getName Obtain thread’s name
getPriority Obtain thread’s priority
isAlive Determine if a thread is still running
join Wait for a thread to terminate
run Entry point for the thread
sleep Suspend a thread for a period of time
start Start a thread by calling its run method
The Main Thread
When a Java program starts up, one thread begins running immediately. This is usually called the
main thread of a program, because it is the one that is executed when our program begins. The main
thread is important for two reasons:
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.
Although the main thread is created automatically when your program is started, it can be controlled
through a Thread object. To do so, It is possible to obtain a reference of main thread by calling the
method currentThread( ), which is a public static member of Thread. Its general form is
static Thread currentThread( )
This method returns a reference to the thread in which it is called. Once have a reference to the main
thread, we can control it just like any other thread.
Example
public class Javathread
{
public static void main(String[] args)
{
Thread t = Thread.currentThread( );
System.out.println("Current thread: " + t);
// change the name of the thread
System.out.println("Name of current thread: " + t.getName());
t.setName("My Thread");
System.out.println("After name change: " + t);
}
}
Output
Current thread: Thread[main,5,main]
Name of current thread: main
After name change: Thread[My Thread,5,main]
In this program, a reference to the current thread (the main thread, in this case) is obtained by
calling currentThread( ), and this reference is stored in the local variable t. Next, the program
displays information about the thread.
This displays, in order: the name of the thread, its priority, and the name of its group.
By default, the name of the main thread is main. Its priority is 5, which is the default value, and
main is also the name of the group of threads to which this thread belongs.
A thread group is a data structure that controls the state of a collection of threads as a whole.
Set the name of a thread by using setName( ). Obtain the name of a thread by calling getName( ).
These methods are members of the Thread class.
Creating a Thread
There are two ways to create a thread:
By extending Thread class
By implementing Runnable interface.
i) Implementing Runnable Interface
The easiest way to create a thread is to create a class that implements the Runnable interface.
To implement Runnable interface, a class need only implement a single method called run( ), which
is declared like this:
public void run( )
Inside run( ), we will define the code that constitutes the new thread
Example
public class MyClass implements Runnable
{
public void run( )
{
System.out.println("MyClass running");
}
}
To execute the run( ) method by a thread, pass an instance of MyClass to a Thread in its
constructor(A constructor in Java is a block of code similar to a method that’s called when an
instance of an object is created).
Thread t1 = new Thread(new MyClass ( ));
t1.start( );
Starting a thread
Start( ) method of Thread class is used to start a newly created thread. It performs 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.
Example
public class Javathread implements Runnable
{
public void run( )
{
System.out.println("Javathread is running...");
}
public static void main(String args[ ])
{
Javathread m1=new Javathread( );
Thread t1 =new Thread(m1);
t1.start( );
}
}
ii) Extending Java Thread
The second way to create a thread is to create a new class that extends Thread, and then to create an
instance of that class. The extending class must override the run( ) method, which is the entry point
for the new thread. It must also call start( ) to begin execution of the new thread. Here is the
preceding program rewritten to extend Thread.
Example
public class MyClass extends Thread
{
public void run( )
{
System.out.println("MyClass running");
}
}
To create and start the above thread you can do like this:
MyClass t1 = new MyClass ( );
t1.start( );
Example
public class Javathread extends Thread
{
public void run( )
{
System.out.println("Javathread is running...");
}
public static void main(String args[ ])
{
Javathread t1=new Javathread( );
t1.start( );
}
}
Example
class NewThread implements Runnable
{
String name; // name of thread
Thread t;
NewThread(String threadname)
{
name = threadname;
t=new Thread(this, name);
System.out.println("New thread: " + t);
}
public void run( ) {
try {
for(int i = 5; i > 0; i--)
{
System.out.println(name + ": " + i);
Thread.sleep(5000);
}}
catch (InterruptedException e)
{
System.out.println(name + "Interrupted");
}
System.out.println(name + " exiting.");
} }
public class Javathread
{
public static void main(String args[])
{
Thread t1 =new Thread(new NewThread("One"));
t1.start( );
Thread t2 =new Thread(new NewThread("Two"));
t2.start( );
Thread t3 =new Thread(new NewThread("Three"));
t3.start( );
try
{
// wait for other threads to end
Thread.sleep(50000);
}
catch (InterruptedException e)
{
System.out.println("Main thread Interrupted");
}
System.out.println("Main thread exiting.");
}
}
Output
New thread: Thread[One,5,main]
New thread: Thread[Two,5,main]
One: 5
New thread: Thread[Three,5,main]
Two: 5
Three: 5
One: 4
Two: 4
Three: 4
One: 3
Three: 3
Two: 3
One: 2
Two: 2
Three: 2
Three: 1
One: 1
Two: 1
One exiting.
Two exiting.
Three exiting.
Main thread exiting.
Using isAlive( ) and join( )
Sometimes one thread needs to know when other thread is terminating.
In java, isAlive( ) and join( ) are two different methods that are used to check whether a thread has
finished its execution or not.
The isAlive( ) method returns true if the thread upon which it is called is still running otherwise it
returns false.
synchronized (resource2)
{
System.out.println("Thread 1: locked resource 2");
}
}
}
};
Thread t2 = new Thread( )
{
public void run( )
{
synchronized (resource2)
{
System.out.println("Thread 2: locked resource 2");
try
{
Thread.sleep(1000);
}
catch (Exception e) { }
synchronized (resource1)
{
System.out.println("Thread 2: locked resource 1");
}
}
}
};
t1.start( );
t2.start( );
}
}
Output
Thread 1: locked resource 1
Thread 2: locked resource 2
Continue running
Daemon Thread in Java
Daemon thread in java is a service provider thread that provides services to the user thread. Its life
depend on the mercy of user threads i.e. when all the user threads dies, JVM terminates this thread
automatically.
It provides services to user threads for background supporting tasks. It has no role in life than to
serve user threads.
Its life depends on user threads.
It is a low priority thread.
Example
Garbage collection thread is one of the system generated daemon thread that runs in background.
These threads run in the background to perform tasks such as garbage collection.
The sole purpose of the daemon thread is that it provides services to user thread for background
supporting task. If there is no user thread, why should JVM keep running this thread. That is why JVM
terminates the daemon thread if there is no user thread.
Methods for Java Daemon thread by Thread class
The java.lang.Thread class provides two methods for java daemon thread.
Example
public class Interthread extends Thread
{
public void run()
{
if(Thread.currentThread().isDaemon())
{//checking for daemon thread
System.out.println("daemon thread work");
}
else
{
System.out.println("user thread work");
}}
public static void main(String[ ] args)
{
Interthread t1=new Interthread( );//creating thread
Interthread t2=new Interthread( );
Interthread t3=new Interthread( );
t1.setDaemon(true);//now t1 is daemon thread
t1.start( );//starting threads
t2.start( );
t3.start( );
}
}
Output
daemon thread work
user thread work
user thread work
Thread Groups
ThreadGroup is a class which is used for creating group of threads. This group of threads are in the
form of a tree structure, in which the initial thread is the parent thread.
Java provides a convenient way to group multiple threads in a single object. In such way, we can
suspend, resume or interrupt group of threads by a single method call.
Java thread group is implemented by java.lang.ThreadGroup class.
A thread is allowed to access information about its own thread group, but it cannot access the
information about its thread group's parent thread group or any other thread groups.
Constructors of ThreadGroup class
There are only two constructors of ThreadGroup class.
Constructor Description
ThreadGroup(String name) creates a thread group with given name.
ThreadGroup(ThreadGroup parent, String name) creates a thread group with given parent group and
name.
Methods of ThreadGroup class
There are many methods in ThreadGroup class. A list of ThreadGroup methods are given below.
void destroy( ) This method destroys the thread group and all of its
subgroups.
int enumerate(Thread[ ] list) This method copies into the specified array every active
thread in the thread group and its subgroups.
int getMaxPriority( ) This method returns the maximum priority of the thread
group.
String getName( ) This method returns the name of the thread group.
ThreadGroup getParent( ) This method returns the parent of the thread group.
void interrupt( ) This method interrupts all threads in the thread group.
boolean isDaemon( ) This method tests if the thread group is a daemon thread
group.
void setDaemon(boolean daemon) This method changes the daemon status of the thread
group.
boolean isDestroyed( ) This method tests if this thread group has been destroyed.
void list( ) This method prints information about the thread group to
the standard output.
boolean parentOf(ThreadGroup g) This method tests if the thread group is either the thread
group argument or one of its ancestor thread groups.
void suspend( ) This method is used to suspend all threads in the thread
group.
void resume( ) This method is used to resume all threads in the thread
group which was suspended using suspend() method.
void setMaxPriority(int pri) This method sets the maximum priority of the group.
void stop( ) This method is used to stop all threads in the thread group.
String toString( ) This method returns a string representation of the Thread
group.
Example
public class Interthread implements Runnable
{
public void run( )
{
System.out.println(Thread.currentThread( ).getName( ));
}
public static void main(String[ ] args)
{
Interthread runnable = new Interthread( );
ThreadGroup tg1 = new ThreadGroup("Parent ThreadGroup");
Thread t1 = new Thread(tg1, runnable,"one");
t1.start( );
Thread t2 = new Thread(tg1, runnable,"two");
t2.start( );
Thread t3 = new Thread(tg1, runnable,"three");
t3.start( );
System.out.println("Thread Group Name: "+tg1.getName( ));
tg1.list( );
}
}
Generic Programming
The Java Generics programming is introduced in JDK 5 to deal with type-safe objects. Before
generics, we can store any type of objects in the collection, i.e., non-generic. Now generics force the
java programmer to store a specific type of objects.
The Object is the superclass of all other classes and Object reference can refer to any type object.
These features lack type safety. Generics add that type safety feature.
The term generics means parameterized types. Parameterized types are important because they
enable you to create classes, interfaces, and methods in which the type of data upon which they
operate is specified as a parameter. Using generics, it is possible to create a single class, for
example, that automatically works with different types of data. A class, interface, or method that
operates on a parameterized type is called generic, as in generic class or generic method.
Advantage of Java Generics
There are mainly 3 advantages of generics. They are as follows:
1) Type-safety: We can hold only a single type of objects in generics. It doesn’t allow to store other
objects.
2) Type casting is not required: There is no need to typecast the object.
3) Compile-Time Checking: It is checked at compile time so problem will not occur at runtime. The
good programming strategy says it is far better to handle the problem at compile time than runtime.
Generic class
A class that can refer to any type is known as a generic class. Here, we are using the T type parameter
to create the generic class of specific type.
Syntax
To use generic collection
class class-name<type-param-list >
Declaring a reference to a generic class
class-name<type-arg-list > var-name = new class-name<type-arg-list > (cons-arg-list);
public class Box<T>
{ }
Box <Type> obj = new Box <Type>( ) // To create an instance of generic class
Example
public class Genclass <T>
{
T obj1; int a;
Genclass(T obj) string ch;
{
obj1 = obj;
}
public T getObject( )
{
return obj1;
}
public static void main(String[] args)
{
Genclass <Integer> iObj = new Genclass<Integer>(15);
System.out.println(iObj.getObject());
Genclass <String> sObj = new Genclass<String>("Welcome");
System.out.println(sObj.getObject());
}
}
run:
15
GeeksForGeeks
Generics Work Only with Objects (Reference Types)
When declaring an instance of a generic type, the type argument passed to the type parameter must
be a class type. You cannot use a primitive type, such as int or char.
Example
Gen<int> intOb = new Gen<int>(53); // Error, can't use primitive type
Multiple Type parameters in Generic classes
Declare more than one type parameter in a generic type. To specify two or more type parameters, simply use a comma-separated
list.
Example
public class Genclass <T, U>
{
T obj1;
U obj2;
Genclass(T objt, U obju)
{
obj1 = objt;
obj2 = obju;
} // constructor
public void getObject( )
{
System.out.println(obj1);
System.out.println(obj2);
}
public static void main(String[ ] args)
{
Genclass <String, Integer> obj = new Genclass<String, Integer>(“Welcome", 15);
obj.getObject( );
}
}
Generic Method
Like the generic class, we can create a generic method that can accept any type of arguments.
Based on the types of the arguments passed to the generic method, the compiler handles each method call
appropriately. Following are the rules to define Generic Methods −
All generic method declarations have a type parameter section delimited by angle brackets (< and >) that precedes the
method's return type ( < E > in the next example).
Each type parameter section contains one or more type parameters separated by commas. A type parameter, also
known as a type variable, is an identifier that specifies a generic type name.
The type parameters can be used to declare the return type and act as placeholders for the types of the arguments
passed to the generic method, which are known as actual type arguments.
A generic method's body is declared like that of any other method. Note that type parameters can represent only
reference types, not primitive types (like int, double and char).
Example
public class Genclass <T>
{
public static < E > void printArray(E[] elements)
{
for ( E element123 : elements)
{
System.out.println(element123 );
}
}
public static void main( String args[] )
{
Integer[ ] intArray = { 10, 20, 30, 40, 50 };
Character[ ] charArray = { 'J', 'A', 'V', 'A', 'T','P','O','I','N','T' };
Double[ ] doubleArray = { 1.1, 2.2, 3.3, 4.4 };
System.out.println( "Printing Integer Array" );
printArray( intArray );
System.out.println( "Printing Character Array" );
printArray( charArray );
System.out.println("Printing Double Array:");
printArray(doubleArray);
}
}
Generic Types Differ Based on Their Type Arguments:
Consider the following Java code.
Test <Integer> iObj = new Test<Integer>(15);
System.out.println(iObj.getObject());
In multitasking, CPU is provided in order to execute While in multithreading also, CPU is provided in
many tasks at a time. order to execute many threads from a process at a
time.
In multitasking, termination of process takes more While in multithreading, termination of thread takes
time. less time.