Unit - 3
Data Abstraction and Multithreading
Abstraction is a feature of OOPs.
The feature allows us to hide the implementation detail from the user and shows only the functionality of the programming to the user. Because the user is not interested to know the implementation.
It is also safe from the security point of view.
The best example of abstraction is a car.
Eg:- When we derive a car, we do not know how is the car moving or how internal components are working? But we know how to derive a car.
It means it is not necessary to know how the car is working, but it is important how to derive a car. The same is an abstraction.
The same principle (as we have explained in the above example) also applied in Java programming
In the language of programming, the code implementation is hidden from the user and only the necessary functionality is shown or provided to the user. We can achieve abstraction in two ways:
- Using Abstract Class
- Using Interface
Abstract classes are the same as normal Java classes the difference is only that an abstract class uses abstract keyword while the normal Java class does not use.
We use the abstract keyword before the class name to declare the class as abstract.
An abstract class contains abstract methods as well as concrete methods.
If we want to use an abstract class, we have to inherit it from the base class.
If the class does not have the implementation of all the methods of the interface, we should declare the class as abstract. It provides complete abstraction. It means that fields are public static and final by default and methods are empty.
The syntax of abstract class is:
Public abstract class ClassName
{
Public abstract methodName();
}
Example of car:
Abstract class Car
{ //abstract method
Abstract void start();
//non-abstract method
Public void stop()
{
System.out.println("The car engine is not started.");
}
} //inherit abstract class
Public class Owner extends Car
{ //defining the body of the abstract method of the abstract class
Void start()
{
System.out.println("The car engine has been started.");
}
Public static void main(String[] args)
{ Owner obj = new Owner();
//calling abstract method
Obj.start();
//calling non-abstract method
Obj.stop();
}
}
OUTPUT:
The car has been started.
The car engine is not started.
In Java, an interface is similar to Java classes.
The difference is only that an interface contains empty methods (methods that do not have method implementation) and variables.
In other words, it is a collection of abstract methods (the method that does not have a method body) and static constants.
The important point about an interface is that each method is public and abstract and does not contain any constructor. Along with the abstraction, it also helps to achieve multiple inheritance.
The implementation of these methods provided by the clients when they implement the interface.
Features of Interface:
- We can achieve total abstraction.
- We can use multiple interfaces in a class that leads to multiple inheritance.
- It also helps to achieve loose coupling.
Syntax
Public interface XYZ
{
Public void method();
}
To use an interface in a class, Java provides a keyword called implements. We provide the necessary implementation of the method that we have declared in the interface.
Example of interface:
Interface CarStart
{
Void start();
}
Interface CarStop
{
Void stop();
}
Public class Car implements CarStart, CarStop
{
Public void start()
{
System.out.println("The car engine has been started.");
}
Public void stop()
{
System.out.println("The car engine has been stopped.");
}
Public static void main(String args[])
{
Car c = new Car();
c.start();
c.stop();
}
}
Output:
The car engine has been started.
The car engine has been stopped.
The relationship between classes and interfaces:
A class extends another class, an interface extends another interface, but a class implements an interface
If a class implements multiple interfaces, or an interface extends multiple interfaces, it is known as multiple inheritance.
Interface Printable
{
Void print();
}
Interface Showable {
Void show();
}
Class A7 implements Printable,Showable
{ public void print(){System.out.println("Hello"); }
Public void show()
{ System.out.println("Welcome"); }
Public static void main(String args[])
{
A7 obj = new A7();
Obj.print();
Obj.show();
}
}
OUTPUT:
Hello
Welcome
A java package is a group of similar types of classes, interfaces and sub-packages.
Package in java can be categorized in two form, built-in package and user-defined package.
There are many built-in packages such as java, lang, awt, javax, swing, net, io, util, sql etc.
Advantage of Java Package
1) Java package is used to categorize the classes and interfaces so that they can be easily maintained.
2) Java package provides access protection.
3) Java package removes naming collision.
How to compile java package
If you are not using any IDE, you need to follow the syntax given below:
Javac -d directory javafilename
How to run java package program
You need to use fully qualified name e.g. Mypack.Simple etc to run the class.
Simple example of java package
The package keyword is used to create a package in java
//save as Simple.java
Package mypack;
Public class Simple
{
Public static void main(String args[]){
System.out.println("Welcome to package");
}
}
To Compile: javac -d. Simple.java
To Run: java mypack.Simple
OUTPUT: Welcome to package
- Java contains many predefined classes that are grouped into categories of related classes called packages.
- Together, these are known as the Java Application Programming Interface (Java API), or the Java class library.
- A great strength of Java is the Java API’s thousands of classes., which represents only a small portion of the reusable components in the Java API.
Java contains many predefined classes that are grouped into categories of related classes called packages. Together, these are known as the Java Application Programming Interface (Java API), or the Java class library. A great strength of Java is the Java API’s thousands of classes. Some key Java API packages that we use in Fig, which represents only a small portion of the reusable components in the Java API.
These are the packages that are defined by the user. First we create a directory myPackage (name should be same as the name of the package). Then create the MyClass inside the directory with the first statement being the package names.
Example:
// Name of the package must be same as the directory// under which this file is saved
Package myPackage;
Public class MyClass
{ public void getNames(String s)
{ System.out.println(s);
}
}
Now we can use the MyClass class in our program.
Public class PrintName
{
Public static void main(String args[])
{ // Initializing the String variable with a value
String name = "GeeksforGeeks";
// Creating an instance of class MyClass in the package.
MyClass obj = new MyClass();
Obj.getNames(name);
}
}
Note: MyClass.java must be saved inside the myPackage directory since it is a part of the package.
There are three ways to access the package from outside the package.
- Import package.*;
- Import package.classname;
- Fully qualified name.
1) Using packagename.*
- If you use package.* then all the classes and interfaces of this package will be accessible but not subpackages.
- The import keyword is used to make the classes and interface of another package accessible to the current package.
Example of package that import the packagename.*
//save by A.java
Package pack;
Public class A {
Public void msg(){System.out.println("Hello");}
}
//save by B.java
Package mypack;
Import pack.*;
Class B{
Public static void main(String args[])
{
A obj = new A();
Obj.msg();
}
}
OUUTPUT: Hello
2) Using packagename.classname
If you import package.classname then only declared class of this package will be accessible.
Example of package by import package.classname
//save by A.java
Package pack;
Public class A
{
Public void msg(){System.out.println("Hello");}
}
//save by B.java
Package mypack;
Import pack.A;
Class B{
Public static void main(String args[]){
A obj = new A();
Obj.msg();
}
}
OUTPUT: Hello
Using fully qualified name
If we use fully qualified name then only declared class of this package will be accessible. Now there is no need to import.
But we need to use fully qualified name every time when you are accessing the class or interface.
It is generally used when two packages have same class name e.g. Java.util and java.sql packages contain Date class.
Example of package by import fully qualified name
//save by A.java
Package pack;
Public class A
{
Public void msg()
{ System.out.println("Hello"); }
}
//save by B.java
Package mypack;
Class B{
Public static void main(String args[]){
Pack.A obj = new pack.A();//using fully qualified name
Obj.msg();
}
}
OUTPUT: Hello
Sequence of the program must be package then import then class.
The Exception Handling in Java is one of the powerful mechanisms to handle the runtime errors so that the normal flow of the application can be maintained.
In Java, an exception is an event that disrupts the normal flow of the program. It is an object which is thrown at runtime.
What is Exception Handling?
Exception Handling is a mechanism to handle runtime errors such as ClassNotFoundException, IOException, SQLException, RemoteException, etc.
There are mainly two types of exceptions: checked and unchecked. An error is considered as the unchecked exception. However, according to Oracle, there are three types of exceptions namely:
1) Checked Exception:
The classes that directly inherit the Throwable class except RuntimeException and Error are known as checked exceptions.
For example, IOException, SQLException, etc. Checked exceptions are checked at compile-time.
1. ClassNotFoundException: The ClassNotFoundException is a kind of checked exception that is thrown when we attempt to use a class that does not exist.
Checked exceptions are those exceptions that are checked by the Java compiler itself.
2. FileNotFoundException: The FileNotFoundException is a checked exception that is thrown when we attempt to access a non-existing file.
3. InterruptedException: InterruptedException is a checked exception that is thrown when a thread is in sleeping or waiting state and another thread attempt to interrupt it.
4. InstantiationException: This exception is also a checked exception that is thrown when we try to create an object of abstract class or interface. That is, InstantiationException exception occurs when an abstract class or interface is instantiated.
5. IllegalAccessException: The IllegalAccessException is a checked exception and it is thrown when a method is called in another method or class but the calling method or class does not have permission to access that method.
6. CloneNotSupportedException: This checked exception is thrown when we try to clone an object without implementing the cloneable interface.
7. NoSuchFieldException: This is a checked exception that is thrown when an unknown variable is used in a program.
8. NoSuchMethodException: This checked exception is thrown when the undefined method is used in a program.
2) Unchecked Exception
The classes that inherit the RuntimeException are known as unchecked exceptions.
For example, ArithmeticException, NullPointerException, ArrayIndexOutOfBoundsException, etc
Unchecked exceptions are not checked at compile-time, but they are checked at runtime.
Let’s see a brief description of them.
1. ArithmeticException: This exception is thrown when arithmetic problems, such as a number is divided by zero, is occurred. That is, it is caused by maths error.
2. ClassCastException: The ClassCastException is a runtime exception that is thrown by JVM when we attempt to invalid typecasting in the program. That is, it is thrown when we cast an object to a subclass of which an object is not an instance.
3. IllegalArgumentException: This runtime exception is thrown by programmatically when an illegal or appropriate argument is passed to call a method. This exception class has further two subclasses:
- Number Format Exception
- Illegal Thread State Exception
Numeric Format Exception: Number Format Exception is thrown by programmatically when we try to convert a string into the numeric type and the process of illegal conversion fails. That is, it occurs due to the illegal conversion of a string to a numeric format.
Illegal Thread State Exception: Illegal Thread State Exception is a runtime exception that is thrown by programmatically when we attempt to perform any operation on a thread but it is incompatible with the current thread state.
4. IndexOutOfBoundsException: This exception class is thrown by JVM when an array or string is going out of the specified index. It has two further subclasses:
- ArrayIndexOutOfBoundsException
- StringIndexOutOfBoundsException
ArrayIndexOutOfBoundsException: ArrayIndexOutOfBoundsException exception is thrown when an array element is accessed out of the index.
StringIndexOutOfBoundsException: StringIndexOutOfBoundsException exception is thrown when a String or StringBuffer element is accessed out of the index.
5. NullPointerException: NullPointerException is a runtime exception that is thrown by JVM when we attempt to use null instead of an object. That is, it is thrown when the reference is null.
6. ArrayStoreException: This exception occurs when we attempt to store any value in an array which is not of array type. For example, suppose, an array is of integer type but we are trying to store a value of an element of another type.
7. IllegalStateException: The IllegalStateException exception is thrown by programmatically when the runtime environment is not in an appropriate state for calling any method.
8. IllegalMonitorStateException: This exception is thrown when a thread does not have the right to monitor an object and tries to access wait(), notify(), and notifyAll() methods of the object.
9. NegativeArraySizeException: The NegativeArraySizeException exception is thrown when an array is created with a negative size.
3) Error
Error is irrecoverable. Some examples of errors are Out Of Memory Error, Virtual Machine Error, Assertion Error etc.
Difference between Checked and Unchecked Exceptions
Checked Exception | Unchecked Exception |
These exceptions are checked at compile time. These exceptions are handled at compile time too. | These exceptions are just opposite to the checked exceptions. These exceptions are not checked and handled at compile time. |
These exceptions are direct subclasses of exception but not extended from RuntimeException class. | They are the direct subclasses of the RuntimeException class. |
The code gives a compilation error in the case when a method throws a checked exception. The compiler is not able to handle the exception on its own. | The code compiles without any error because the exceptions escape the notice of the compiler. These exceptions are the results of user-created errors in programming logic. |
These exceptions mostly occur when the probability of failure is too high. | These exceptions occur mostly due to programming mistakes. |
Common checked exceptions include IOException, DataAccessException, InterruptedException, etc. | Common unchecked exceptions include ArithmeticException, InvalidClassException, NullPointerException, etc. |
These exceptions are propagated using the throws keyword. | These are automatically propagated. |
It is required to provide the try-catch and try-finally block to handle the checked exception. | In the case of unchecked exception it is not mandatory. |
For every thread JVM (Java virtual machine) creates a run-time stack.
- Each and every call performed in a thread is stored in the stack.
- Each entry in the run-time stack is known as activation record or stack frame.
- After completing every method call by the thread is removed from the corresponding entry of the stack.
- After completing all the methods, the stack will be empty and that run-time stack will be destroyed by the JVM before terminating the thread.
Case 1: Normally (graceful termination)
Construction of run-time Stack:
1. Firstly, the main thread will call main() method and the corresponding entry will be in the stack.
2. After that main() method is calling fun() method, which will store in the stack.
3. In the fun() method, moreFun() method is called. Therefore at last moreFun() will be stored in stack.
4. Finally, moreFun() is not calling any method and it will print Hello Geeks!
// Java program to illustrate run time
// Run-time stack mechanism in
// normal flow of Exception handling
Class Geeks {
Public static void main(String[] args)
{
Fun();
}
Public static void fun()
{
MoreFun();
}
Public static void moreFun()
{
System.out.println("Hello Geeks!");
}
}
Output:
Hello Geeks!
Destruction of run-time stack: After printing Hello Geeks! Its corresponding entry will be removed from the stack and it will go to fun() method and there is nothing for execution that’s why the entry of fun() method is removed from the stack and so on. When the stack is empty then the run-time stack is destroyed by the JVM.
Case 2: Abnormally (abnormal termination)
Construction of run-time Stack:
1. The example below have Arithmetic Exception at method moreFun() location, the JVM will check any exception handling code is there. If not, then method moreFun() will be responsible to create exception object because of exception are raised on method moreFun() and corresponding entry from the stack will be removed and the control goes to method fun().
2. JVM again go to the caller method to check if it is having any exception handling code are not. If not JVM terminates the method abnormally and deleted the corresponding entry from the stack.
3. The above process continues until main thread. If the main thread(main method) doesn’t have any exception handling code the JVM also terminates the main method abnormally and default exception handler is responsible to print the exception message to the output screen which is the part of JVM.
// Java program to illustrate run time
// Run-time stack mechanism in
// normal flow of Exception handling
Public class ExceptionHandling {
Public static void main(String[] args)
{
Fun();
}
Public static void fun()
{
MoreFun();
System.out.println("Method fun");
}
Public static void moreFun()
{
System.out.println(10 / 0);
System.out.println("Method moreFun");
}
}
Runtime error:
Exception in thread "main" java.lang.ArithmeticException: / by zero
At ExceptionHandling.moreFun(ExceptionHandling.java:16)
At ExceptionHandling.fun(ExceptionHandling.java:11)
At ExceptionHandling.main(ExceptionHandling.java:7)
Destruction of run-time stack
- The default exception handler is a Java method; it can be overridden.
- This means that it is possible for an application to write a new default exception handler. This method looks like this:
Void uncaughtException(Thread t, Throwable o)
- The default exception handler method, which is called as a final handler to take care of any exceptions not caught by the thread in the run() method.
- This is a method of the Thread Group class.
- The default exception handler is a method of the Thread Group class. It is called only when an exception is thrown from the run() method.
- The thread is technically completed when the run() method returns,
- In Java, we can create our own exceptions that are derived classes of the Exception class. Creating our own Exception is known as custom exception or user-defined exception.
- Java custom exceptions are used to customize the exception according to user need.
- Consider the example 1 in which Invalid Age Exception class extends the Exception class.
- Using the custom exception, we can have your own exception and message. Here, we have passed a string to the constructor of superclass i.e. Exception class that can be obtained using getMessage() method on the object we have created.
Following are few of the reasons to use custom exceptions:
- To catch and provide specific treatment to a subset of existing Java exceptions.
- Business logic exceptions: These are the exceptions related to business logic and workflow. It is useful for the application users or the developers to understand the exact problem.
In order to create custom exception, we need to extend Exception class that belongs to java.lang package.
Consider the following example, where we create a custom exception named WrongFileNameException:
Public class WrongFileNameException extends Exception
{
Public WrongFileNameException(String errorMessage)
{ super(errorMessage);
}
}
There are many rules if we talk about method overriding with exception handling. Some of the rules are listed below:
- If the superclass method does not declare an exception
- If the superclass method does not declare an exception, subclass overridden method cannot declare the checked exception but it can declare unchecked exception.
- If the superclass method declares an exception
- If the superclass method declares an exception, subclass overridden method can declare same, subclass exception or no exception but cannot declare parent exception.
Java provides five keywords that are used to handle the exception. The following table describes each.
Keyword | Description |
Try | The "try" keyword is used to specify a block where we should place an exception code. It means we can't use try block alone. The try block must be followed by either catch or finally. |
Catch | The "catch" block is used to handle the exception. It must be preceded by try block which means we can't use catch block alone. It can be followed by finally block later. |
Finally | The "finally" block is used to execute the necessary code of the program. It is executed whether an exception is handled or not. |
Throw | The "throw" keyword is used to throw an exception. |
Throws | The "throws" keyword is used to declare exceptions. It specifies that there may occur an exception in the method. It doesn't throw an exception. It is always used with method signature. |
A) try block:
a) Syntax of try block with catch block:
Try {
//Block of statement}
Catch(Exception Handler class)
{
}
b) Syntax of try block with finally block:
Try {
//Block of statement}
Finally {
}
c) Syntax of try block with catchand finally block:
Try {
//Block of statement}
Catch(Exception Handler class)
{
} finally{
}
B) Catch block:
a) Syntax of try block with catch block:
Try {
//Block of statement}
Catch(Exception Handler class)
{
}
b) Multiple catch block:
Syntax of try block with catch block:
Try {
//Block of statement}
Catch(Exception Handlersub class)
{
}catch(Exception Handler super class){
}
C) Nested try block:
Syntax of nested try block
Try{ // block of statement
Try{
// block of statement
}
Catch(Exception Handler class)
{
}
Catch(Exception Handler class)
{
}
D) Finally:
a) Syntax of finally without catch
Try{
//block of statement
}
Finally {
}
b) Syntax of finally with catch
Try {
//Block of statement}
Catch(Exception Handler class)
{
} finally{
}
E) throw:
Syntax:
Throw exception_object;
F) throws:
Syntax:
MethodName () throws comma separated list of exceptionClassNames{}
Difference between throw and throws
Throw keyword | Throws keyword |
|
|
Difference between final, finally and finalize
- The final, finally, and finalize are keywords in Java that are used in exception handling. Each of these keywords has a different functionality.
- The basic difference between final, finally and finalize is that the final is an access modifier, finally is the block in Exception Handling and finalize is the method of object class.
Key | Final | Finally | Finalize |
Definition | Final is the keyword and access modifier which is used to apply restrictions on a class, method or variable. | Finally is the block in Java Exception Handling to execute the important code whether the exception occurs or not. | Finalize is the method in Java which is used to perform clean up processing just before object is garbage collected. |
Applicable to | Final keyword is used with the classes, methods and variables. | Finally block is always related to the try and catch block in exception handling. | Finalize() method is used with the objects. |
Functionality | (1) Once declared, final variable becomes constant and cannot be modified. | (1) finally block runs the important code even if exception occurs or not. | Finalize method performs the cleaning activities with respect to the object before its destruction. |
Execution | Final method is executed only when we call it. | Finally block is executed as soon as the try-catch block is executed. It's execution is not dependant on the exception. | Finalize method is executed just before the object is destroyed. |
Java provides us facility to create our own exceptions which are basically derived classes of Exception. For example MyException in below code extends the Exception class.
We pass the string to the constructor of the super class- Exception which is obtained using “getMessage()” function on the object created.
// A Class that represents use-defined expception
Class MyException extends Exception
{
Public MyException(String s)
{ // Call constructor of parent Exception
Super(s);
}
}
// A Class that uses above MyException
Public class Main
{
// Driver Program
Public static void main(String args[])
{
Try
{
// Throw an object of user defined exception
Throw new MyException("Geeks Geeks");
}
Catch (MyException ex)
{
System.out.println("Caught");
// Print the message from MyException object
System.out.println(ex.getMessage());
}
}
}
Output:
Caught
Geeks Geeks
In the a
- File Not Found Exception is a common type of IO Exception while working with the file system:
Try
{
New FileReader(new File("/invalid/file/location"));
} catch (FileNotFoundException e)
{
LOGGER.info("FileNotFoundException caught!");
}
- Null Pointer Exception:
If an application attempts to use null where it actually requires an object instance, the method will throw a Null Pointer Exception.
- Number Format Exception
This type of exception occurs when you pass a string to a method that cannot be converted to a number. For example, consider the following code
//program to demonstrate the Number Format Exception
Class Sample NumberFormat
{
Public static void main(String args[])
{
Try
{//test is not a number
Int n=Integer.parseInt(“Test”);
System.out.println(“Number Format exception”);
}
Catch (NumberFormatException e)
{
System.out.println(“Number Format exception”);
}
}}
- Arithmetic Exception
This type of exception occurs when you perform an incorrect arithmetic operation. For example, if you divide any number by zero, it will display such an exception. Let us consider the following code
//program to demonstrate the Arithmetic Exception
Class Sample_ArithmeticException
{ Public static void main(String args[])
{ try
{
Int P=30, q=0;
Int r= p / q;
System.out.println(“Result =” + r);
}
Catch (ArithmeticException e)
{System.out.println(“Number cannot be divided by zero”);
}
}}
These are commonly used exception.
- 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.
- 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.
Multitasking is a process of executing multiple tasks simultaneously. We use multitasking to utilize the CPU. Multitasking can be achieved in two ways:
- Process-based Multitasking (Multiprocessing)
- Thread-based Multitasking (Multithreading)
1) Process-based Multitasking (Multiprocessing)
- Each process has an address in memory i.e. each process allocates a separate memory area.
- A process is heavyweight.
- Cost of communication between the process is high.
- Switching from one process to another requires some time for saving and loading registers, memory maps, updating lists, etc.
2) Thread-based Multitasking (Multithreading)
- Threads share the same address space.
- A thread is lightweight.
- Cost of communication between the thread is low.
Java provides Thread class to achieve thread programming.
There are two ways to create a thread:
- By extending Thread class
- By implementing Runnable interface.
By extending 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.
Java Thread Example by extending Thread class
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…
By implementing 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:
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.
Java Thread Example by implementing Runnable interface
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);
t1.start();
}
}
OUTPUT:
Thread is running…
- The Thread class provides methods to change and get the name of a thread.
- By default, each thread has a name i.e. thread-0, thread-1 and so on.
- We can change the name of the thread by using setName() method. The syntax of setName() and getName() methods are given below:
- Public String getName(): is used to return the name of a thread.
- Public void setName(String name): is used to change the name of a thread.
Example of naming a thread
Class TestMultiNaming1 extends Thread
{
Public void run()
{
System.out.println("running...");
}
Public static void main(String args[])
{
TestMultiNaming1 t1=new TestMultiNaming1();
TestMultiNaming1 t2=new TestMultiNaming1();
System.out.println("Name of t1:"+t1.getName());
System.out.println("Name of t2:"+t2.getName());
t1.start();
t2.start();
t1.setName("Sonoo Jaiswal");
System.out.println("After changing name of t1:"+t1.getName());
}
}
OUTPUT:
Name of t1: Thread-0
Name of t2: Thread-1
Id of t1: 8
Running…
After changeling name of t1: Sonoo Jaiswal
Running…
In a Multithreading environment, thread scheduler assigns processor to a thread based on priority of thread. Whenever we create a thread in Java, it always has some priority assigned to it.
Priority can either be given by JVM while creating the thread or it can be given by programmer explicitly.
Accepted value of priority for a thread is in range of 1 to 10. There are 3 static variables defined in Thread class for priority.
public static int MIN_PRIORITY: This is minimum priority that a thread can have. Value for this is 1.
public static int NORM_PRIORITY: This is default priority of a thread if do not explicitly define it. Value for this is 5.
public static int MAX_PRIORITY: This is maximum priority of a thread. Value for this is 10.
Get and Set Thread Priority:
Public final int getPriority():
Java.lang.Thread.getPriority() method returns priority of given thread.
Public final void setPriority int(newPriority):
Java.lang.Thread.setPriority() method changes the priority of thread to the value new Priority. This method throws Illegal Argument Exception if value of parameter new Priority goes beyond minimum(1) and maximum(10) limit.
We can prohibit a thread execution by using these methods
1. Yield()
2. Join()
3. Sleep()
1. Yield()
yield() method causes, to halt present executing thread for giving the chance to rest await threads of same priority
If there are no waiting threads or all waiting threads have low priority then the same thread will continue it's execution once again.
Syntax:
Public static void yield()
This thread does not return any value
Example:
Class MyThread extends Thread
{
Public void run( ) {
For(int i=0;i<10;i++)
{ Thread.yield(); --------------------> 1
System.out.println("child thread");
}
}
}
Class ThreadYieldDemo
{ public static void main(String[] args)
{ MyThread t = new MyThread();
t.start();
For(int i=0;i<10;i++){
System.out.println("main thread");
}
}
}
Explanation:
If we are commenting Line1 the both threads will be executed simultaneously & we cannot expat exact execution order If we are not commenting Line1 then the chance of completing main thread is high because child thread always calls yield()
2. Join() method
If a thread wants to wait until completing some other thread, then we should go for join method
join() method is overloaded and every join() throws Interrupted Exception.
Hence, whenever we are using join() method compulsory we should handle Interrupted Exception, either by try-catch or by throws otherwise we will get compile time error.
3. Sleep() method
If a thread do not want to perform any operation for a particular amount of time(just pausing) then we should go for sleep() method
Whenever we are using sleep() method compulsory we should handle Interrupted Exception otherwise we will get compile time error.
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.
The synchronization is mainly used to
- To prevent thread interference.
- To prevent consistency problem.
Types of Synchronization
There are two types of synchronization
- Process Synchronization
- Thread Synchronization
Thread Synchronization
There are two types of thread synchronization mutual exclusive and inter-thread communication.
- Mutual Exclusive
- Synchronized method.
- Synchronized block.
- Static synchronization.
- Cooperation (Inter-thread communication in java)
Mutual Exclusive
Mutual Exclusive helps keep threads from interfering with one another while sharing data. It can be achieved by using the following three ways:
- By Using 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.
2. By Using Synchronized Block:
Synchronized block can be used to perform synchronization on any specific resource of the method.
Points to Remember
- Synchronized block is used to lock an object for any shared resource.
- Scope of synchronized block is smaller than the method.
- A Java synchronized block doesn't allow more than one JVM, to provide access control to a shared resource.
- The system performance may degrade because of the slower working of synchronized keyword.
- Java synchronized block is more efficient than Java synchronized method.
Syntax
Synchronized (object reference expression)
{
//code block
}
3. By Using Static Synchronization
If you make any static method as synchronized, the lock will be on the class not on object.
Concept of Lock in Java
- Synchronization is built around an internal entity known as the lock or monitor.
- Every object has a lock associated with it. By convention, a thread that needs consistent access to an object's fields has to acquire the object's lock before accessing them, and then release the lock when it's done with them.
- The package java.util.concurrent.locks contains several lock implementations.
Inter-thread communication or Co-operation is all about allowing synchronized threads to communicate with each other.
Cooperation (Inter-thread communication) is a mechanism in which a thread is paused running in its critical section and another thread is allowed to enter (or lock) in the same critical section to be executed.
It is implemented by following methods of Object class:
- Wait()
- Notify()
- NotifyAll()
1) wait() method
The wait() method causes current thread to release the lock and wait until either another thread invokes the notify() method or the notifyAll() method for this object, or a specified amount of time has elapsed.
The current thread must own this object's monitor, so it must be called from the synchronized method only otherwise it will throw exception.
Java
Method | Description |
Public final void wait()throws Interrupted Exception | It waits until object is notified. |
Public final void wait(long timeout)throws Interrupted Exception | It waits for the specified amount of time. |
2) notify() method
The notify() method wakes up a single thread that is waiting on this object's monitor.
If any threads are waiting on this object, one of them is chosen to be awakened. The choice is arbitrary and occurs at the discretion of the implementation.
Syntax: public final void notify()
3) notifyAll() method
Wakes up all threads that are waiting on this object's monitor.
Syntax: public final void notifyAll()
Understanding the process of inter-thread communication
The point-to-point explanation of the above diagram is as follows:
- Threads enter to acquire lock.
- Lock is acquired by on thread.
- Now thread goes to waiting state if you call wait() method on the object. Otherwise, it releases the lock and exits.
- If you call notify() or notifyAll() method, thread moves to the notified state (runnable state).
- Now thread is available to acquire lock.
- After completion of the task, thread releases the lock and exits the monitor state of the object.
Why wait(), notify() and notifyAll() methods are defined in Object class not Thread class?
It is because they are related to lock and object has a lock.
Difference between wait and sleep
Wait() | Sleep() |
The wait() method releases the lock. | The sleep() method doesn't release the lock. |
It is a method of Object class | It is a method of Thread class |
It is the non-static method | It is the static method |
It should be notified by notify() or notifyAll() methods | After the specified amount of time, sleep is completed. |
Deadlock in Java is a part of multithreading.
Deadlock can occur in a situation when a thread is waiting for an object lock, that is acquired by another thread and second thread is waiting for an object lock that is acquired by first thread.
Since, both threads are waiting for each other to release the lock, the condition is called deadlock.
How to avoid deadlock?
A solution for a problem is found at its roots. In deadlock it is the pattern of accessing the resources A and B, is the main issue.
To solve the issue, we will have to simply re-order the statements where the code is accessing shared resources.
How to Avoid Deadlock in Java?
Deadlocks cannot be completely resolved. But we can avoid them by following basic rules mentioned below:
- Avoid Nested Locks: We must avoid giving locks to multiple threads, this is the main reason for a deadlock condition. It normally happens when you give locks to multiple threads.
- Avoid Unnecessary Locks: The locks should be given to the important threads. Giving locks to the unnecessary threads that cause the deadlock condition.
- Using Thread Join: A deadlock usually happens when one thread is waiting for the other to finish. In this case, we can use join with a maximum time that a thread will take.
Demon thread in java is a service provider thread that provides services to the user thread.
Its life depends on the mercy of user threads i.e. when all the user threads dies, JVM terminates this thread automatically.
There are many java daemon threads running automatically e.g. Gc, finalizer etc.
The jconsole tool provides information about the loaded classes, memory usage, running threads etc.
Some Points to remember for Demon Thread in Java
- 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.
Methods for Java Demon thread by Thread class
The java.lang.Thread class provides two methods for java daemon thread.
Method | Description |
Public void setDaemon(boolean status) | Is used to mark the current thread as demon thread or user thread. |
Public boolean isDemon() | Is used to check that current is demon. |
Real world performance improvement for multithreading
1. It depends on many factors.
2. In general, the most optimistic improvement that one can hope for is reduction of runtime by factor of number of cores.
3. In most cases this is unachievable because of the need for threads to synchronize with one another.
4. In worst case, not only is there no improvement due to lack of parallelism, but also the overhead of synchronization as well as cache contention can make the runtime much worse than the single threaded program.
5. Peak memory use often increases linearly by number of threads because each thread needs to operate on data of their own.
6. Total CPU time usage, and therefore energy use also increases due to extra time spent on synchronization. This is relevant to systems that operate on battery power as well as those that have poor heat management (both apply to phones and laptops).
7. Binary size would be marginally larger due to extra code that deals with threads.
Inner Classes (Nested Classes)
Java inner class or nested class is a class that is declared inside the class or interface.
We use inner classes to logically group classes and interfaces in one place to be more readable and maintainable.
it can access all the members of the outer class, including private data members and methods.
Syntax of Inner class
Class Java_Outer_class
{ //code
Class Java_Inner_class
{ //code }
}
Advantage of Java inner classes
- Nested classes represent a particular type of relationship that is it can access all the members (data members and methods) of the outer class, including private.
- Nested classes are used to develop more readable and maintainable code because it logically group classes and interfaces in one place only.
- Code Optimization: It requires less code to write.
Need of Java Inner class
Sometimes users need to program a class in such a way so that no other class can access it.
Therefore, it would be better if you include it within other classes.
If all the class objects are a part of the outer object then it is easier to nest that class inside the outer class.
That way all the outer class can access all the objects of the inner class.
Types of Nested classes
There are two types of nested classes non-static and static nested classes. The non-static nested classes are also known as inner classes.
- Non-static nested class (inner class)
- Member inner class
- Anonymous inner class
- Local inner class
- Static nested class
Type | Description |
Member Inner Class | A class created within class and outside method. |
Anonymous Inner Class | A class created for implementing an interface or extending class. The java compiler decides its name. |
Local Inner Class | A class was created within the method. |
Static Nested Class | A static class was created within the class. |
Nested Interface | An interface created within class or interface. |
A non-static class that is created inside a class but outside a method is called member inner class.
It is also known as a regular inner class.
It can be declared with access modifiers like public, default, private, and protected.
Syntax:
Class Outer
{ //code
Class Inner{ //code }
}
Java Member Inner Class Example
In this example, we are creating a msg() method in the member inner class that is accessing the private data member of the outer class.
Class TestMemberOuter1
{ private int data=30;
Class Inner{
Void msg(){System.out.println("data is "+data);
}
}
Public static void main(String args[]){
TestMemberOuter1 obj=new TestMemberOuter1();
TestMemberOuter1.Inner in=obj.new Inner();
In.msg();
}
}
OUTPUT:
Data is 30
How to instantiate Member Inner class in Java?
An object or instance of a member's inner class always exists within an object of its outer class.
The new operator is used to create the object of member inner class with slightly different syntax.
The general form of syntax to create an object of the member inner class is as follows:
Syntax:
OuterClassReference.new MemberInnerClassConstructor();
Example:
Obj.new Inner();
Here, OuterClassReference is the reference of the outer class followed by a dot which is followed by the new operator.
Internal working of Java member inner class:
- The java compiler creates two class files in the case of the inner class.
- The class file name of the inner class is "Outer$Inner". If you want to instantiate the inner class, you must have to create the instance of the outer class.
- In such a case, an instance of inner class is created inside the instance of the outer class.
Internal code generated by the compiler:
- The Java compiler creates a class file named Outer$Inner in this case.
- The Member inner class has the reference of Outer class that is why it can access all the data members of Outer class including private.
A static class is a class that is created inside a class, is called a static nested class in Java.
It cannot access non-static data members and methods. It can be accessed by outer class name.
- It can access static data members of the outer class, including private.
- The static nested class cannot access non-static (instance) data members or
Java static nested class example with instance method
TestOuter1.java
Class TestOuter1
{
Static int data=30;
Static class Inner
{
Void msg()
{ System.out.println("data is "+data);}
} //closing static class inner
Public static void main(String args[]){
TestOuter1.Inner obj=new TestOuter1.Inner();
Obj.msg();
}
}
OUTPUT:
Data is 30
Explanation:
In this example, you need to create the instance of static nested class because it has instance method msg(). But you don't need to create the object of the Outer class because the nested class is static and static properties, methods, or classes can be accessed without an object.
- A class i.e., created inside a method, is called local inner class in java.
- Local Inner Classes are the inner classes that are defined inside a block.
- Generally, this block is a method body. Sometimes this block can be a for loop, or an if clause.
- Local Inner classes are not a member of any enclosing classes.
- They belong to the block they are defined within, due to which local inner classes cannot have any access modifiers associated with them.
- However, they can be marked as final or abstract. These classes have access to the fields of the class enclosing it.
- If you want to invoke the methods of the local inner class, you must instantiate this class inside the method.
Java local inner class example
LocalInner1.java
Public class localInner1
{
Private int data=30;//instance variable
Void display()
{
Class Local
{
Void msg()
{ System.out.println(data); }
}
Local l=new Local();
l.msg();
}
Public static void main(String args[])
{
LocalInner1 obj=new localInner1();
Obj.display();
}
}
OUTPUT:
30
- Java anonymous inner class is an inner class without a name and for which only a single object is created.
- An anonymous inner class can be useful when making an instance of an object with certain "extras" such as overloading methods of a class or interface, without having to actually subclass a class.
- In simple words, a class that has no name is known as an anonymous inner class in Java. It should be used if you have to override a method of class or interface. Java Anonymous inner class can be created in two ways:
- Class (may be abstract or concrete).
- Interface
Java anonymous inner class example using class
TestAnonymousInner.java
Abstract class Person
{
Abstract void eat();
}
Class TestAnonymousInner
{
Public static void main(String args[])
{
Person p=new Person(){
Void eat()
{ System.out.println("nice fruits"); }
};
p.eat();
}
}
OUTPUT:
Nice fruit
References:
1. Programming in Java. Second Edition. Oxford Higher Education. (Sachin Malhotra/Saura V Choudhary)
2. CORE JAVA For Beginners. (Rashmi Kanta Das), Vikas Publication
3. JAVA Complete Reference (9th Edition) Herbait Schelidt.