0% found this document useful (0 votes)
3 views59 pages

Java Unit-III Notes

This document covers exception handling and multithreading in Java, detailing the concepts, benefits, and hierarchy of exceptions, as well as the usage of keywords such as try, catch, throw, throws, and finally. It explains the types of exceptions, including checked and unchecked exceptions, and provides examples of handling exceptions using try-catch blocks. Additionally, it discusses multithreading concepts, including thread life cycle, synchronization, and inter-thread communication.

Uploaded by

Danush Teja
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views59 pages

Java Unit-III Notes

This document covers exception handling and multithreading in Java, detailing the concepts, benefits, and hierarchy of exceptions, as well as the usage of keywords such as try, catch, throw, throws, and finally. It explains the types of exceptions, including checked and unchecked exceptions, and provides examples of handling exceptions using try-catch blocks. Additionally, it discusses multithreading concepts, including thread life cycle, synchronization, and inter-thread communication.

Uploaded by

Danush Teja
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

UNIT – III

Exception handling and Multithreading-- Concepts of exception handling,


benefits of exception handling,
exception hierarchy,
usage of try, catch, throw, throws and finally,
built in exceptions,
creating own exception subclasses.
String handling, exploring [Link].
Differences between multithreading and multitasking,
thread life cycle, creating threads,
thread priorities,
synchronizing threads,
inter thread communication,
thread groups.
Exception Handling in Java
An exception is a problem that arises at the time of program execution.
When an exception occurs, it disrupts the program execution flow. When an exception occurs, the program
execution gets terminated, and the system generates an error.
Error vs Exception
Error: An Error indicates serious problem that a reasonable application should not try to catch.
Exception: Exception indicates conditions that a reasonable application might try to catch.
To avoid abnormal termination of program execution we use the exception handling mechanism.
For example there are 20 statements in your program and there occurs an exception at statement 5, the rest of the
code will not be executed i.e. statement 6 to 20 will not be executed. If we perform exception handling, the rest
of the statement will be executed. That is why we use exception handling in Java.
Reasons for Exception Occurrence
Several reasons lead to the occurrence of an exception. A few of them are as follows.
● When we try to open a file that does not exist may lead to an exception.
● When the user enters invalid input data, it may lead to an exception.
● When a network connection has lost during the program execution may lead to an exception.
● When we try to access the memory beyond the allocated range may lead to an exception.
● The physical device problems may also lead to an exception.
Types of Exception
There are mainly two types of exceptions: checked and unchecked. Here, an error is considered as the unchecked
exception. According to Oracle, there are three types of exceptions:
1. Checked Exception
2. Unchecked Exception
3. Error
● Checked Exception - An exception that is checked by the compiler at the time of compilation is called
a checked exception.
e.g. IOException, SQLException etc.
● Unchecked Exception - An exception that can not be caught by the compiler but occurrs at the
time of program execution is called an unchecked exception.(Unchecked exceptions are not checked at compile-
time, but they are checked at runtime.)
e.g. ArithmeticException, NullPointerException, ArrayIndexOutOfBoundsException etc.
● Error - Error is irrecoverable e.g. OutOfMemoryError, VirtualMachineError, AssertionError etc.
How exceptions handled in Java?
In java, the exception handling mechanism uses five keywords namely try, catch, finally, throw, and throws.
Checked Exceptions
The checked exception is an exception that is checked by the compiler during the compilation process to confirm
whether the exception is handled by the programmer or not. If it is not handled, the compiler displays a
compilation error using built-in classes.
The following are a few built-in classes used to handle checked exceptions in java.
● IOException
● FileNotFoundException
● ClassNotFoundException
● SQLException
● DataAccessException
● InstantiationException
● UnknownHostException
The checked exception is also known as a compile-time exception.
import [Link].*;
public class CheckedExceptions {
public static void main(String[] args) {
File f_ref = new File("C:\\Users\\User\\Desktop\\Today\\[Link]");
try {
FileReader fr = new FileReader(f_ref);
}catch(Exception e) {
[Link](e);
}
}
}
output:

Unchecked Exceptions
The unchecked exception is an exception that occurs at the time of program execution. The unchecked exceptions
are not caught by the compiler at the time of compilation.
The unchecked exceptions are generally caused due to bugs such as logic errors, improper use of resources, etc.
The following are a few built-in classes used to handle unchecked exceptions in java.

● ArithmeticException
● NullPointerException
● NumberFormatException
● ArrayIndexOutOfBoundsException
● StringIndexOutOfBoundsException
The unchecked exception is also known as a runtime exception.
public class UncheckedException {
public static void main(String[] args) {
int list[] = {10, 20, 30, 40, 50};
[Link](list[6]); //ArrayIndexOutOfBoundsException
String msg=null;
[Link]([Link]()); //NullPointerException
String name="abc";
int i=[Link](name); //NumberFormatException
}
}
OUTPUT:

Exception class hierarchy


In java, the built-in classes used to handle exceptions have the following class hierarchy.
Exception Models in Java
In java, there are two exception models. Java programming language has two models of exception handling.
The exception models that Java supports are as follows.
● Termination Model
● Resumptive Model
Let's look into details of each exception model.
Termination Model
In the termination model, when a method encounters an exception, further processing in that method is
terminated and control is transferred to the nearest catch block that can handle the type of exception
encountered.
In other words we can say that in the termination model, the error is so critical there is no way to get back to
where the exception occurred.
Resumptive Model
The alternative of termination model is resumptive model. In resumptive model, the exception handler is
expected to do something to stable the situation, and then the faulting method is retried. In resumptive model
we hope to continue the execution after the exception is handled.
In resumptive model we may use a method call that want resumption like behavior. We may also place the try
block in a while loop that keeps re-entering the try block util the result is satisfactory.
Uncaught Exceptions in Java
In java, assume that, if we do not handle the exceptions in a program. In this case, when an exception occurs in
a particular function, then Java prints a exception message with the help of uncaught exception handler.
The uncaught exceptions are the exceptions that are not caught by the compiler but automatically caught and
handled by the Java built-in exception handler.
When an uncaught exception occurs, the JVM calls a special private method known
dispatchUncaughtException( ), on the Thread class in which the exception occurs and terminates the thread.
The Division by zero exception is one of the example for uncaught exceptions.
EXAMPLE:
import [Link];
public class UncaughtExceptionExample {
public static void main(String[] args) {
Scanner read = new Scanner([Link]);
[Link]("Enter the a and b values: ");
int a = [Link]();
int b = [Link]();
int c = a / b;
[Link](a + "/" + b +" = " + c);
}
}
OUTPUT:

Java Exception Keywords


There are given some scenarios where unchecked exceptions may occur. They are as follows:
1) A scenario where ArithmeticException occurs
If we divide any number by zero, there occurs an ArithmeticException.
int a=50/0;//ArithmeticException
2) A scenario where NullPointerException occurs
If we have a null value in any variable, performing any operation on the variable throws a
NullPointerException.
String s=null;
[Link]([Link]());//NullPointerException
3) A scenario where NumberFormatException occurs
The wrong formatting of any value may occur NumberFormatException. Suppose I have a string variable that
has characters, converting this variable into digit will occur NumberFormatException.
String s="abc";
int i=[Link](s);//NumberFormatException
4) A scenario where ArrayIndexOutOfBoundsException occurs
If you are inserting any value in the wrong index, it would result in ArrayIndexOutOfBoundsException as
shown below:
int a[]=new int[5];
a[10]=50; //ArrayIndexOutOfBoundsException
try and catch in Java
In java, the try and catch, both are the keywords used for exception handling.
The keyword try is used to define a block of code that will be tests the occurrence of an exception. The
keyword catch is used to define a block of code that handles the exception occured in the respective try block.
If an exception occurs at the particular statement of try block, the rest of the block code will not execute. So, it
is recommended not to keeping the code in try block that will not throw an exception.
Java try block must be followed by either catch or finally block.
The uncaught exceptions are the exceptions that are not caught by the compiler but automatically caught and
handled by the Java built-in exception handler.
Both try and catch are used as a pair. Every try block must have one or more catch blocks. We can not use try
without atleast one catch, and catch alone can be used (catch without try is not allowed).
Syntax
try{
code to be tested
}
catch(ExceptionType object){
code for handling the exception
}
Java catch block is used to handle the Exception by declaring the type of exception within the parameter. The
declared exception must be the parent class exception ( i.e., Exception) or the generated exception type.
However, the good approach is to declare the generated type of exception.
The catch block must be used after the try block only. You can use multiple catch block with a single try block.
Problem without exception handling
EXAMPLE:
public class TryCatchExample1 {
public static void main(String[] args) {
int data=50/0; //may throw exception
[Link]("rest of the code");
}
}
OUTPUT:

The rest of the code is not executed (in such case, the rest of the code statement is not printed).
There can be 100 lines of code after exception. So all the code after exception will not be executed.
Using exception handling
Let's see the solution of the above problem by a java try-catch block.
EXAMPLE:
public class TryCatchExample2 {
public static void main(String[] args) {
try {
int data=50/0; //may throw exception
}
//handling the exception
catch(ArithmeticException e) {
[Link](e); }
[Link]("rest of the code");
} }
EXAMPLE:
public class TryCatchExample6 {
public static void main(String[] args) {
int i=50;
int j=0;
int data;
try {
data=i/j; //may throw exception
}
// handling the exception
catch(Exception e) {
// resolving the exception in catch block
[Link](i/(j+2));
}
} }
along with try block, we also enclose exception code in a catch block.
EXAMPLE:
public class TryCatchExample7 {
public static void main(String[] args) {
try {
int data1=50/0; //may throw exception
}
// handling the exception
catch(Exception e) {
// generating the exception in catch block
int data2=50/0; //may throw exception
}
[Link]("rest of the code");
} }
An example to handle another unchecked exception.
EXAmPLE:
public class TryCatchExample9 {
public static void main(String[] args) {
try {
int arr[]= {1,3,5,7};
[Link](arr[10]); //may throw exception
}
// handling the array exception
catch(ArrayIndexOutOfBoundsException e) {
[Link](e);
}
[Link]("rest of the code");
}
}

Working of try-catch block in Java


The JVM firstly checks whether the exception is handled or not. If exception is not handled, JVM provides a
default exception handler that performs the following tasks:
● Prints out exception description.
● Prints the stack trace (Hierarchy of methods where the exception occurred).
● Causes the program to terminate.
But if exception is handled by the application programmer, normal flow of the application is maintained i.e. rest
of the code is executed.
Multiple catch clauses
In java programming language, a try block may has one or more number of catch blocks. That means a single
try statement can have multiple catch clauses.
When a try block has more than one catch block, each catch block must contain a different exception type to be
handled.
Points to remember
The try block generates only one exception at a time, and at a time only one catch block is executed.
When there are multiple catch blocks, the order of catch blocks must be from the most specific exception
handler to most general.
The catch block with Exception class handler must be defined at the last.
Example
public class TryCatchExample {
public static void main(String[] args) {
try {
int list[] = new int[5];
list[2] = 10;
list[4] = 2;
list[10] = list[2] / list[4];
}
catch(ArithmeticException ae) {
[Link]("Problem info: Value of divisor can not be ZERO.");
}
catch(ArrayIndexOutOfBoundsException aie) {
[Link]("Problem info: ArrayIndexOutOfBoundsException has occured.");
}
catch(Exception e) {
[Link]("Problem info: Unknown exception has occured."); } } }

To handle the exception without maintaining the order of exceptions (i.e. from most specific to most general).
EXAMPLE:
class MultipleCatchBlock5{
public static void main(String args[]){
try{
int a[]=new int[5];
a[5]=30/0;
}
catch(Exception e){[Link]("common task completed");}
catch(ArithmeticException e){[Link]("task1 is completed");}
catch(ArrayIndexOutOfBoundsException e){[Link]("task 2 completed");}
[Link]("rest of the code...");
}
}
OUTPUT: Compile time error
Nested try statements
The try block within a try block is known as nested try block in java.
Sometimes a situation may arise where a part of a block may cause one error and the entire block itself may
cause another error. In such cases, exception handlers have to be nested.
When there are nested try blocks, each try block must have one or more separate catch blocks.
In the case of nested try blocks, if an exception occurs in the inner try block and its catch blocks are unable to
handle it then it transfers the control to the outer try's catch block to handle it.
Syntax:
try {
try {
}
catch(Exception e) {
} }
catch(Exception e) {
}
Example
public class TryCatchExample {
public static void main(String[] args) {
try {
int list[] = new int[5];
list[2] = 10;
list[4] = 2;
list[0] = list[2] / list[4];
try {
list[10] = 100;
}
catch(ArrayIndexOutOfBoundsException aie) {
[Link]("Problem info: ArrayIndexOutOfBoundsException has occured.");
}
}
catch(ArithmeticException ae) {
[Link]("Problem info: Value of divisor can not be ZERO.");
}
catch(Exception e) {
[Link]("Problem info: Unknown exception has occured.");
}
}
}
throw, throws, and finally keywords in Java
Throw keyword
The throw keyword is used to throw an exception instance explicitly from a try block to corresponding catch
block. That means it is used to transfer the control from try block to corresponding catch block.
The throw keyword must be used inside the try blcok. When JVM encounters the throw keyword, it stops the
execution of try block and jump to the corresponding catch block.
Using throw keyword only object of Throwable class or its sub classes can be thrown.
Using throw keyword only one exception can be thrown.
The throw keyword must followed by an throwable instance.
Syntax
throw instance;
Here the instance must be throwable instance and it can be created dynamically using new operator.
Example
import [Link];
public class Sample {
public static void main(String[] args) {
Scanner input = new Scanner([Link]);
int num1, num2, result;
[Link]("Enter any two numbers: ");
num1 = [Link]();
num2 = [Link]();
try {
if(num2 == 0)
throw new ArithmeticException("Division by zero is not posible");
result = num1 / num2;
[Link](num1 + "/" + num2 + "=" + result);
}
catch(ArithmeticException ae) {
[Link]("Problem info: " + [Link]());
}
[Link]("End of the program");
} }

throws keyword in Java


The throws keyword specifies the exceptions that a method can throw to the default handler and does not
handle itself. That means when we need a method to throw an exception automatically, we use throws keyword
followed by method declaration
When a method throws an exception, we must put the calling statement of method in try-catch block.
The Java throws keyword is used to declare an exception. It gives an information to the programmer that there
may occur an exception so it is better for the programmer to provide the exception handling code so that normal
flow can be maintained.
Syntax
return_type method_name() throws exception_class_name{
//method code
}
Advantage of Java throws keyword
 Checked Exception can be propagated (forwarded in call stack).
 It provides information to the caller of the method about the exception.
EXAMPLE:
import [Link];
public class ThrowsExample {
int num1, num2, result;
Scanner input = new Scanner([Link]);
void division() throws ArithmeticException {
[Link]("Enter any two numbers: ");
num1 = [Link]();
num2 = [Link]();
result = num1 / num2;
[Link](num1 + "/" + num2 + "=" + result);
}
public static void main(String[] args) {
try {
new ThrowsExample().division();
}
catch(ArithmeticException ae) {
[Link]("Problem info: " + [Link]());
}
[Link]("End of the program");
}
}
Example of java throws clause which describes that checked exceptions can be propagated by throws keyword.
import [Link];
class Testthrows1{
void m()throws IOException{
throw new IOException("device error");//checked exception }
void n()throws IOException{ m(); }
void p(){
try{ n();
}catch(Exception e){[Link]("exception handled");}
}
public static void main(String args[]){
Testthrows1 obj=new Testthrows1();
obj.p();
[Link]("normal flow...");
} }
OUTPUT: exception handled
normal flow...
If you are calling a method that declares an exception, you must either caught or declare the exception.
There are two cases:
1. Case1:You caught the exception i.e. handle the exception using try/catch.
2. Case2:You declare the exception i.e. specifying throws with the method.
In the first case, you handle the exception, the code will be executed fine whether the exception occurs during
the program or not.
import [Link].*;
class M{
void method()throws IOException{
throw new IOException("device error"); } }
public class Testthrows2{
public static void main(String args[]){
try{ M m=new M();
[Link]();
}catch(Exception e){[Link]("exception handled");}
[Link]("normal flow..."); } }
Output:
exception handled
normal flow...
In the case 2
A) In case you declare the exception, if exception does not occur, the code will be executed fine.
B) In case you declare the exception if exception occures, an exception will be thrown at runtime because
throws does not handle the exception.
import [Link].*;
class M{
void method()throws IOException{
[Link]("device operation performed");
} }
class Testthrows3{
public static void main(String args[])throws IOException{//declare exception
M m=new M();
[Link]();
[Link]("normal flow...");
} }
Output:
device operation performed
normal flow...
Program if exception occurs
import [Link].*;
class M{
void method()throws IOException{
throw new IOException("device error");
} }
class Testthrows4{
public static void main(String args[])throws IOException{//declare exception
M m=new M();
[Link]();
[Link]("normal flow...");
} }
Output: Runtime Exception
Difference between throw and throws in Java

finally keyword in Java


Java finally block is a block that is used to execute important code such as closing connection, stream etc.
Java finally block is always executed whether exception is handled or not.
Java finally block follows try or catch block.
Use of finally block is optional.
The basic purpose of finally keyword is to cleanup resources allocated by try block, such as closing file, closing
database connection, etc.
If you don't handle exception, before terminating the program, JVM executes finally block(if any)
Example
import [Link];
public class FinallyExample {
public static void main(String[] args) {
int num1, num2, result;
Scanner input = new Scanner([Link]);
[Link]("Enter any two numbers: ");
num1 = [Link]();
num2 = [Link]();
try {
if(num2 == 0)
throw new ArithmeticException("Division by zero");
result = num1 / num2;
[Link](num1 + "/" + num2 + "=" + result);
}
catch(ArithmeticException ae) {
[Link]("Problem info: " + [Link]());
}
finally {
[Link]("The finally block executes always");
}
[Link]("End of the program");
}
}
java finally example where exception occurs and not handled.
class TestFinallyBlock1{
public static void main(String args[]){
try{
int data=25/0;
[Link](data);
}
catch(NullPointerException e){[Link](e);}
finally{[Link]("finally block is always executed");}
[Link]("rest of the code...");
}
}
Output: finally block is always executed
Exception in thread main [Link]:/ by zero

java finally example where exception doesn't occur.


class TestFinallyBlock{
public static void main(String args[]){
try{
int data=25/5;
[Link](data);
}
catch(NullPointerException e){[Link](e);}
finally{[Link]("finally block is always executed");}
[Link]("rest of the code...");
} }
Output: 5
finally block is always executed
rest of the code...
Java Exception propagation
An exception is first thrown from the top of the stack and if it is not caught, it drops down the call stack to the
previous method,If not caught there, the exception again drops down to the previous method, and so on until
they are caught or until they reach the very bottom of the call [Link] is called exception propagation.
By default Unchecked Exceptions are forwarded in calling chain (propagated).
class TestExceptionPropagation1{
void m(){ int data=50/0; }
void n(){ m(); }
void p(){
try{ n(); }catch(Exception e){[Link]("exception handled");} }
public static void main(String args[]){
TestExceptionPropagation1 obj=new TestExceptionPropagation1();
obj.p();
[Link]("normal flow...");
} }
By default, Checked Exceptions are not forwarded in calling chain (propagated).
Program which describes that checked exceptions are not propagated
class TestExceptionPropagation2{
void m(){
throw new [Link]("device error");//checked exception
}
void n(){ m(); }
void p(){
try{ n(); }catch(Exception e){[Link]("exception handeled");}
}
public static void main(String args[]){
TestExceptionPropagation2 obj=new TestExceptionPropagation2();
obj.p();
[Link]("normal flow");
} }
Output:Compile Time Error
Built-in Exceptions in Java
The Java programming language has several built-in exception class that support exception handling. Every
exception class is suitable to explain certain error situations at run time.
All the built-in exception classes in Java were defined a package [Link].
List of checked exceptions in Java

List of unchecked exceptions in Java


Creating Own Exceptions in Java
The Java programming language allow us to create our own exception classes which are basically subclasses
built-in class Exception.
To create our own exception class simply create a class as a subclass of built-in Exception class.
We may create constructor in the user-defined exception class and pass a string to Exception class constructor
using super(). We can use getMessage() method to access the string.
Sometimes it is required to develop meaningful exceptions based on the application requirements. We can
create our own exceptions by extending Exception class in Java
User-defined exceptions in Java are also known as Custom Exceptions.
Steps to create a Custom Exception with an Example
● Custom Exception class is the custom exception class this class is extending Exception class.
● Create one local variable message to store the exception message locally in the class object.
● We are passing a string argument to the constructor of the custom exception object. The constructor set
the argument string to the private string message.
● toString() method is used to print out the exception message.
● We are simply throwing a CustomException using one try-catch block in the main method and observe
how the string is passed while creating a custom exception. Inside the catch block, we are printing out
the message.
class InvalidProductException extends Exception
{
public InvalidProductException(String s)
{
// Call constructor of parent Exception
super(s);
}
}
public class Example1
{
void productCheck(int weight) throws InvalidProductException{
if(weight<100){
throw new InvalidProductException("Product Invalid");
} }
public static void main(String args[])
{
Example1 obj = new Example1();
try
{
[Link](60);
}
catch (InvalidProductException ex)
{
[Link]("Caught the exception");
[Link]([Link]());
} } }

1. String Handling in Java

1.1 What is a String in Java?


• A String is a sequence of characters.
• In Java, String is an object of the String class (not a primitive type).
• Strings are immutable — once created, the content cannot be changed.
• Strings are stored in the String Constant Pool (inside the heap memory).

Example — Immutability in action:

String s = "Hello";
[Link]("World"); // creates a NEW object, does not modify s
[Link](s); // Output: Hello

// The original string s remains unchanged!

NOTE The concat() method returns a new String object. The original variable s still
points to "Hello". To capture the result, you must assign it: s =
[Link]("World");

1.2 Why are Strings Immutable?


Immutability in Java Strings is a deliberate design decision with three key benefits:

1. 1. Security — Strings are widely used in sensitive operations (database connections, file paths,
network URLs). If they were mutable, a malicious class could change the value after validation, causing
a security breach.
2. Thread Safety — Multiple threads can share the same String object without synchronization because
no thread can modify it.
3. Memory Efficiency — The String Constant Pool allows Java to reuse existing String objects instead of
creating duplicates, saving heap memory.

// Two variables pointing to SAME object in the pool:


String a = "Java";
String b = "Java";
[Link](a == b); // true (same reference)
[Link]([Link](b)); // true (same content)

// Using "new" forces a NEW object outside the pool:


String c = new String("Java");
[Link](a == c); // false (different reference)
[Link]([Link](c)); // true (same content)

1.3 Commonly Used String Methods


The String class provides a rich set of built-in methods for manipulation, comparison, and searching. All
methods return new String objects (immutability).

1. length()

• Returns the total number of characters in the string.


• Spaces and special characters are also counted.

String str = "Hello";


[Link]([Link]()); // Output: 5

String s2 = "Java Programming";


[Link]([Link]()); // Output: 16

2. charAt(int index)

• Returns the character at the specified index position.


• Indexing starts from 0 (zero-based).
• Throws StringIndexOutOfBoundsException if index is invalid.
String str = "Hello";
// 01234 <- index positions
[Link]([Link](0)); // Output: H
[Link]([Link](1)); // Output: e
[Link]([Link](4)); // Output: o

3. substring(int beginIndex, int endIndex)

• Extracts a portion of the string.


• beginIndex is inclusive (character at this index IS included).
• endIndex is exclusive (character at this index is NOT included).
• If endIndex is omitted, it extracts from beginIndex to end.

String str = "Hello, World!";


// 0123456789...
[Link]([Link](0, 5)); // Output: Hello
[Link]([Link](7)); // Output: World!
[Link]([Link](7, 12)); // Output: World

4. concat(String str)

• Joins (concatenates) two strings together.


• Returns a new String — does NOT modify the original.
• The + operator can also be used for concatenation in Java.

String str = "Hello";


String result = [Link](" World");
[Link](result); // Output: Hello World
[Link](str); // Output: Hello (unchanged!)

// Equivalent using + operator:


String result2 = str + " World"; // Output: Hello World

5. equals(Object obj)

• Compares the content of two strings.


• Case-sensitive ("Hello" != "hello").
• Use equalsIgnoreCase() for case-insensitive comparison.
• Always use equals() to compare String content — never use == (which compares references).

String str = "Hello";


[Link]([Link]("Hello")); // true
[Link]([Link]("hello")); // false
[Link]([Link]("HELLO")); // true

// WRONG WAY (compares references, not content):


String a = new String("Hello");
String b = new String("Hello");
[Link](a == b); // false!

6. compareTo(String anotherString)

• Compares two strings lexicographically (dictionary order).


• Based on Unicode values of characters.
◦ Returns 0 if both strings are equal
◦ Returns a positive value if the calling string is greater
◦ Returns a negative value if the calling string is smaller

[Link]("Apple".compareTo("Banana")); // Negative (-1)


[Link]("Banana".compareTo("Apple")); // Positive (+1)
[Link]("Apple".compareTo("Apple")); // 0

// It compares character by character:


// A (65) vs B (66) => 65 - 66 = -1 (Apple comes before Banana)

7. toUpperCase() and toLowerCase()

• toUpperCase() — converts all characters to UPPERCASE.


• toLowerCase() — converts all characters to lowercase.
• Returns a new String; original remains unchanged.

String str = "Hello World";


[Link]([Link]()); // HELLO WORLD
[Link]([Link]()); // hello world
[Link](str); // Hello World (original unchanged)

8. trim()

• Removes leading and trailing whitespace (spaces, tabs).


• Does NOT remove spaces within the string.
• Very useful when processing user input.

String s = " Hello World ";


[Link]([Link]()); // "Hello World"
[Link]([Link]().length()); // 11

// Note: spaces inside the string are NOT removed:


String s2 = " Java Program ";
[Link]([Link]()); // "Java Program"

9. replace(char oldChar, char newChar)

• Replaces ALL occurrences of a character with another character.


• Can also replace substrings: replace(String old, String new).
• Returns a new String with replacements applied.

String str = "Hello";


[Link]([Link]('l', 'x')); // Hexxo

// Replace substring:
String s2 = "I love Java. Java is great!";
[Link]([Link]("Java", "Python"));
// Output: I love Python. Python is great!

1.4 String Methods — Quick Reference Table

Method Description Example Output

length() Returns number of characters "Hello".length() → 5

charAt(i) Character at index i "Hello".charAt(1) → e

substring(b,e) Extract from index b to e-1 "Hello".substring(1,4) →


ell

concat(s) Join two strings "Hi".concat(" Java") → Hi


Java

equals(s) Compare content (case-sensitive) "Hi".equals("hi") → false

equalsIgnoreCase(s) Compare ignoring case "Hi".equalsIgnoreCase("HI")


→ true

compareTo(s) Lexicographic comparison "A".compareTo("B") → -1

toUpperCase() Convert to uppercase "hello".toUpperCase() →


HELLO

toLowerCase() Convert to lowercase "HELLO".toLowerCase() →


hello

trim() Remove leading/trailing spaces " Hi ".trim() → "Hi"

replace(o,n) Replace all occurrences "Hello".replace('l','x') →


Hexxo

indexOf(s) First index of substring "Hello".indexOf("l") → 2

contains(s) Check if substring exists "Hello".contains("ell") →


true

isEmpty() Check if string is empty "".isEmpty() → true

startsWith(s) Check starting substring "Java".startsWith("Ja") →


true
endsWith(s) Check ending substring "Java".endsWith("va") →
true

1.5 Complete Demonstration Program

public class StringMethods {


public static void main(String[] args) {
String str = "Hello, World!";

[Link]("Original String : " + str);


[Link]("Length : " + [Link]());
[Link]("Char at index 1 : " + [Link](1));
[Link]("Substring (0,5) : " + [Link](0, 5));
[Link]("Concatenated : " + [Link](" Welcome!"));
[Link]("Equals check : " + [Link]("Hello, World!"));
[Link]("CompareTo Java : " + [Link]("Hello, Java!"));
[Link]("Uppercase : " + [Link]());
[Link]("Lowercase : " + [Link]());
[Link]("Trimmed : " + " Hello ".trim());
[Link]("Replace o->a : " + [Link]('o', 'a'));
}
}

Original String: Hello, World! | Length: 13 | Char at index 1: e | Substring (0,5):


Hello | Concatenated: Hello, World! Welcome! | Equals check: true |
OUTPUT
Uppercase: HELLO, WORLD! | Lowercase: hello, world! | Trimmed: Hello |
Replace o->a: Hella, Warld!

StringBuilder and StringBuffer: Mutable sequences of characters.


 StringBuilder is not synchronized (faster, not thread-safe).
Example: StringBuilder sb = new StringBuilder("Hello");
[Link](", World!");
[Link]([Link]()); // Output: Hello, World!
 StringBuffer is synchronized (slower, thread-safe).
Example: StringBuffer sbf = new StringBuffer("Hello");
[Link](", World!");
[Link]([Link]()); // Output: Hello, World!

2. Exploring the [Link] Package

2.1 Overview of [Link]


The [Link] package is one of the most important packages in Java. It provides a wide range of utility classes
and interfaces for:
• Data structures (collections) — ArrayList, LinkedList, HashMap, HashSet, etc.
• Date and time — Date, Calendar, LocalDate (Java 8+)
• Input/output utilities — Scanner
• Mathematical utilities — Random, Arrays, Collections
• Sorting and searching algorithms

To use classes from [Link], you must import them: import [Link];
IMPORT
or use the wildcard import [Link].*;

2.2 ArrayList
ArrayList is a resizable array implementation. Unlike regular arrays, it can grow and shrink dynamically.

import [Link];

ArrayList<String> list = new ArrayList<>();


[Link]("Apple"); // Add element
[Link]("Banana");
[Link]("Cherry");

[Link](list); // [Apple, Banana, Cherry]


[Link]([Link](1)); // Banana
[Link]([Link]()); // 3

[Link]("Banana"); // Remove by value


[Link](0); // Remove by index
[Link]([Link]("Cherry")); // true

2.3 HashMap
HashMap stores data as key-value pairs. Keys are unique; values can be duplicated.

import [Link];

HashMap<String, Integer> map = new HashMap<>();


[Link]("Alice", 90); // Add key-value pair
[Link]("Bob", 85);
[Link]("Carol", 92);

[Link]([Link]("Alice")); // 90
[Link]([Link]("Bob")); // true
[Link]([Link]()); // 3

// Iterate over all entries:


for (String key : [Link]()) {
[Link](key + " -> " + [Link](key));
}

2.4 Scanner — Reading User Input


The Scanner class is used to read input from the keyboard ([Link]) or other sources.

import [Link];
Scanner sc = new Scanner([Link]);

[Link]("Enter your name: ");


String name = [Link](); // Read a full line

[Link]("Enter your age: ");


int age = [Link](); // Read an integer

[Link]("Hello, " + name + "! Age: " + age);

[Link](); // Always close the Scanner when done

2.5 Collections Class — Sorting & Searching


The Collections class provides static utility methods for operating on collections.

import [Link];
import [Link];

ArrayList<Integer> nums = new ArrayList<>();


[Link](40); [Link](10); [Link](30); [Link](20);

[Link](nums); // [10, 20, 30, 40]


[Link](nums); // [40, 30, 20, 10]
[Link]([Link](nums)); // 40
[Link]([Link](nums)); // 10

// Binary search (list must be sorted first):


[Link](nums);
int index = [Link](nums, 30);
[Link]("Found at index: " + index); // 2

2.6 [Link] Key Classes Summary

Class / Interface Purpose Key Methods

ArrayList<E> Dynamic resizable array add(), get(), remove(), size(),


contains()

LinkedList<E> Doubly-linked list addFirst(), addLast(),


removeFirst(), peek()

HashMap<K,V> Key-value pairs (unordered) put(), get(), remove(),


containsKey()

HashSet<E> Unique elements, unordered add(), remove(), contains(),


size()

TreeMap<K,V> Sorted key-value pairs put(), get(), firstKey(),


lastKey()

Scanner Read keyboard/file input nextLine(), nextInt(),


nextDouble()

Collections Static utility methods sort(), reverse(), max(), min()

Arrays Array utility methods sort(), binarySearch(), fill(),


toString()

Random Generate random numbers nextInt(), nextDouble(),


nextBoolean()

Date Represents date and time getTime(), toString()

Difference between Multithreading and Multitasking


The main difference between multitasking and multi-threading is that one process is divided into many threads
that can run concurrently in multi-threading, whereas multi-tasking entails running multiple independent
processes or tasks. While multi-threading enhances the performance of a single process, multi-tasking is used to
manage multiple processes at once.

Multithreading
Process and Thread
Process --A process is an instance of a program that is being executed. When we run a program, it does not
execute directly. It takes some time to follow all the steps required to execute the program, and following these
execution steps is known as a process.
A process can create other processes to perform multiple tasks at a time; the created processes are known as clone
or child process, and the main process is known as the parent process. Each process contains its own memory
space and does not share it with the other processes.
Thread --A thread is the subset of a process and is also known as the lightweight process. A process can have
more than one thread, and these threads are managed independently by the scheduler. All the threads within one
process are interrelated to each other.
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.
Advantages of Java Multithreading
1) It doesn't block the user because threads are independent and you can perform multiple operations at the same
time.
2) You can perform many operations together, so it saves time.
3) Threads are independent, so it doesn't affect other threads if an exception occurs in a single thread.
Multitasking
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. In other words, 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.
Differences between thread-based multitasking and process- based multitasking

Process-Based Multitasking Thread-Based Multitasking

In process-based multitasking, two or


In thread-based multitasking, two or more threads can be run
more processes and programs can be
concurrently.
run concurrently.

In process-based multitasking, a
process or a program is the smallest In thread-based multitasking, a thread is the smallest unit.
unit.

The program is a bigger unit. Thread is a smaller unit.

Process-based multitasking requires


Thread-based multitasking requires less overhead.
more overhead.

The process requires its own address


Threads share the same address space.
space.

The process to Process communication


Thread to Thread communication is not expensive.
is expensive.
Process-Based Multitasking Thread-Based Multitasking

Here, it is unable to gain access over


It allows taking gain access over idle time taken by the CPU.
the idle time of the CPU.

It is a comparatively heavyweight. It is comparatively lightweight.

It has a faster data rate for multi-tasking


because two or more
It has a comparatively slower data rate multi-tasking.
processes/programs can be run
simultaneously.

Example: Using a browser we can navigate through the webpage


Example: We can listen to music and
and at the same time download a file. In this example, navigation
browse the internet at the same time.
is one thread, and downloading is another thread. Also in a word-
The processes in this example are the
processing application like MS Word, we can type text in one
music player and browser.
thread, and spell checker checks for mistakes in another thread.

Sr.
Multitasking Multithreading
No

Multitasking enables users to perform multiple Multithreading involves creating multiple threads within a
1
tasks concurrently using the CPU. single process, enhancing computational power.

Multitasking often requires the CPU to switch Multithreading also involves CPU context switching
2
between different tasks. between threads.

In multitasking, processes have separate In multithreading, threads share the same memory space
3
memory spaces. within a process.

Multithreading focuses on concurrent execution within a


Multitasking can include multiprocessing,
4 single process and doesn't necessarily involve
where multiple processes run independently.
multiprocessing.

Multitasking allocates CPU time for executing Multithreading provides CPU time for executing multiple
5
multiple tasks concurrently. threads within a process concurrently.

In multitasking, processes typically do not


In multithreading, threads share the same resources within
6 share resources; each has its own allocated
a process.
resources.

Multitasking may be slower than


Multithreading is generally faster due to reduced overhead
7 multithreading, depending on the system and
in managing threads.
tasks.

Terminating a process in multitasking can take Terminating a thread in multithreading is typically faster
8
more time. as it involves less cleanup.
Sr.
Multitasking Multithreading
No

Multitasking provides isolation and memory Multithreading lacks isolation and memory protection, as
9
protection between processes. threads share the same memory space.

Multitasking is crucial for developing efficient Multithreading is essential for developing efficient
10
programs to perform multiple concurrent tasks. operating systems and applications.

Multitasking involves running multiple Multithreading divides a single process into multiple
11
independent processes or tasks concurrently. threads that can execute concurrently.

In multitasking, multiple processes or tasks run


In multithreading, multiple threads within a process share
12 simultaneously, each with its own processor
the same memory space and resources.
and resources.

Each process or task in multitasking has its Threads in multithreading share the same memory space
13
own memory space and dedicated resources. and resources of the parent process.

Multitasking manages multiple processes and Multithreading manages concurrent execution within a
14
enhances system efficiency. single process, improving system efficiency.

Examples of multitasking include running Examples of multithreading include splitting a video


15 multiple applications on a computer or encoding task into multiple threads or implementing a
multiple servers on a network. responsive user interface in an application.

Java thread life cycle


Following are the stages of the life cycle −
● New − A new thread begins its life cycle in the new state. It remains in this state until the program starts
the thread. It is also referred to as a born thread.
Thread t1 = new Thread();
● Runnable − After a newly born thread is started, the thread becomes runnable. A thread in this state is
considered to be executing its task.
[Link]( );
● Waiting − Sometimes, a thread transitions to the waiting state while the thread waits for another thread
to perform a task. A thread transitions back to the runnable state only when another thread signals the
waiting thread to continue executing.
When a thread calls run( ) method, then the thread is said to be Running. The run( ) method of a thread called
automatically by the start( ) method.
A yield() method is a static method of thread class and it can stop the currently executing thread and will give a
chance to other waiting threads of the same priority
If in case there are no waiting threads or if all the waiting threads have low priority then the same thread will
continue its execution
● Timed Waiting − A runnable thread can enter the timed waiting state for a specified interval of time. A
thread in this state transitions back to the runnable state when that time interval expires or when the event
it is waiting for occurs.
A thread in the Running state may move into the blocked state due to various reasons like sleep( ) method called,
wait( ) method called, suspend( ) method called, and join( ) method called, etc.
When a thread is in the blocked or waiting state, it may move to Runnable state due to reasons like sleep time
completed, waiting time completed, notify( ) or notifyAll( ) method called, resume( ) method called, etc.
[Link](1000);
wait(1000);
resume();
wait();
suspened();
join( )
notify();
notifyAll();
● Terminated (Dead) − A runnable thread enters the terminated state when it completes its task or
otherwise terminates.
A thread in the Running state may move into the dead state due to either its execution completed or the stop( )
method called. The dead state is also known as the terminated state.
Creating threads in java
In java, a thread is a lightweight process. Every java program executes by a thread called the main thread. When
a java program gets executed, the main thread created automatically. All other threads called from the main
thread.
The java programming language provides two methods to create threads, and they are listed below.
 Using Thread class (by extending Thread class)
 Uisng Runnable interface (by implementing Runnable interface)
Extending Thread class
The java contains a built-in class Thread inside the [Link] package. The Thread class contains all the methods
that are related to the threads.
To create a thread using Thread class, follow the step given below.
Step-1: Create a class as a child of Thread class. That means, create a class that extends Thread class.
Step-2: Override the run( ) method with the code that is to be executed by the thread. The run( ) method
must be public while overriding.
Step-3: Create the object of the newly created class in the main( ) method.
Step-4: Call the start( ) method on the object created in the above step.
EXAMPLE:
class SampleThread extends Thread{
public void ran() {
[Link]("Thread is under Running...");
for(int i= 1; i<=10; i++) {
[Link]("i = " + i);
} } }
public class My_Thread_Test {
public static void main(String[] args) {
SampleThread t1 = new SampleThread();
[Link]("Thread about to start...");
[Link]();
} }
Implementng Runnable interface
The java contains a built-in interface Runnable inside the [Link] package. The Runnable interface implemented
by the Thread class that contains all the methods that are related to the threads.
To create a thread using Runnable interface, follow the step given below.
Step-1: Create a class that implements Runnable interface.
Step-2: Override the run( ) method with the code that is to be executed by the thread. The run( ) method
must be public while overriding.
Step-3: Create the object of the newly created class in the main( ) method.
Step-4: Create the Thread class object by passing above created object as parameter to the Thread class
constructor.
Step-5: Call the start( ) method on the Thread class object created in the above step.
EXAMPLE:
class SampleThread implements Runnable{

public void run() {


[Link]("Thread is under Running...");
for(int i= 1; i<=10; i++) {
[Link]("i = " + i);
}
}
}
public class My_Thread_Test {
public static void main(String[] args) {
SampleThread threadObject = new SampleThread();
Thread thread = new Thread(threadObject);
[Link]("Thread about to start...");
[Link]();
}
}
More about Thread class
The Thread class in java is a subclass of Object class and it implements Runnable interface. The Thread class is
available inside the [Link] package.
Syntax
class Thread extends Object implements Runnable{
...
}
The Thread class has the following consructors.
 Thread( )
 Thread( String threadName )
 Thread( Runnable objectName )
 Thread( Runnable objectName, String threadName )
The Thread class in java also contains methods like stop( ), destroy( ), suspend( ), and resume( ). But they are
depricated.
The Thread classs contains the following Methods.
The previous methods are invoked on a particular Thread object. The following methods in the Thread class are
static. Invoking one of the static methods performs the operation on the currently running thread.
Java Thread Priority
Every Java thread has a priority that helps the operating system determine the order in which threads are
scheduled.
Java thread priorities are in the range between MIN_PRIORITY (a constant of 1) and MAX_PRIORITY (a
constant of 10). By default, every thread is given priority NORM_PRIORITY (a constant of 5).
Threads with higher priority are more important to a program and should be allocated processor time before
lower-priority threads. However, thread priorities cannot guarantee the order in which threads execute and are
very much platform dependent.
In a java programming language, every thread has a property called priority. Most of the scheduling algorithms
use the thread priority to schedule the execution sequence. In java, the thread priority range from 1 to 10.
Priority 1 is considered as the lowest priority, and priority 10 is considered as the highest priority. The thread
with more priority allocates the processor first.
The java programming language Thread class provides two methods setPriority(int), and getPriority( ) to
handle thread priorities.
The Thread class also contains three constants that are used to set the thread priority, and they are listed below.
 MAX_PRIORITY - It has the value 10 and indicates highest priority.
 NORM_PRIORITY - It has the value 5 and indicates normal priority.
 MIN_PRIORITY - It has the value 1 and indicates lowest priority.
The default priority of any thread is 5 (i.e. NORM_PRIORITY).
setPriority( ) method
The setPriority( ) method of Thread class used to set the priority of a thread. It takes an integer range from 1 to
10 as an argument and returns nothing (void).
[Link](4);
or
[Link](MAX_PRIORITY);
getPriority( ) method
The getPriority( ) method of Thread class used to access the priority of a thread. It does not takes anyargument
and returns name of the thread as String.
String threadName = [Link]();
In java, it is not guaranteed that threads execute according to their priority because it depends on JVM
specification that which scheduling it chooses.
Example
import [Link].*;
class ThreadDemo extends Thread {
public void run()
{
[Link]("Inside run method");
}
public static void main(String[] args)
{
ThreadDemo t1 = new ThreadDemo();
ThreadDemo t2 = new ThreadDemo();
ThreadDemo t3 = new ThreadDemo();
// Default 5
[Link]("t1 thread priority : " + [Link]());
// Default 5
[Link]("t2 thread priority : " + [Link]());
// Default 5
[Link]("t3 thread priority : " + [Link]());
[Link](2);
[Link](5);
[Link](8);

// [Link](21); will throw


// IllegalArgumentException

// 2
[Link]("t1 thread priority : " + [Link]());

// 5
[Link]("t2 thread priority : " + [Link]());

// 8
[Link]("t3 thread priority : "+ [Link]());
// Main thread
// Displays the name of
// currently executing Thread
[Link]( "Currently Executing Thread : " +
[Link]().getName());

[Link]( "Main thread priority : " +


[Link]().getPriority());

// Main thread priority is set to 10


[Link]().setPriority(10);
[Link]( "Main thread priority : " +
[Link]().getPriority());
}
}
OUTPUT:
t1 thread priority : 5
t2 thread priority : 5
t3 thread priority : 5
t1 thread priority : 2
t2 thread priority : 5
t3 thread priority : 8
Currently Executing Thread : main
Main thread priority : 5
Main thread priority : 10
Java Thread Synchronisation
The java programming language supports multithreading. The problem of shared resources occurs when two or
more threads get execute at the same time. In such a situation, we need some way to ensure that the shared
resource will be accessed by only one thread at a time, and this is performed by using the concept called
synchronization.
The synchronization is the process of allowing only one thread to access a shared resource at a time.
The synchronization is mainly used to
 To prevent thread interference.
 To prevent consistency problem.
Types of Synchronization
There are two types of synchronization
1. Process Synchronization
2. Thread Synchronization
Thread Synchronization
There are two types of thread synchronization mutual exclusive and inter-thread communication.
1. Mutual Exclusive
a. Synchronized method.
b. Synchronized block.
c. static synchronization.
2. Cooperation (Inter-thread communication in java)
1). Mutual Exclusion
Using the mutual exclusion process, we keep threads from interfering with one another while they accessing the
shared resource. In java, mutual exclusion is achieved using the following concepts.
Synchronized method
When a method created using a synchronized keyword, it allows only one object to access it at a time. When an
object calls a synchronized method, it put a lock on that method so that other objects or thread that are trying to
call the same method must wait, until the lock is released. Once the lock is released on the shared resource, one
of the threads among the waiting threads will be allocated to the shared resource.

Example
class Table{
synchronized void printTable(int n) {
for(int i = 1; i <= 10; i++)
[Link](n + " * " + i + " = " + i*n);
}
}
class MyThread_1 extends Thread{
Table table = new Table();
int number;
MyThread_1(Table table, int number){
[Link] = table;
[Link] = number;
}
public void run() {
[Link](number);
}
}
class MyThread_2 extends Thread{
Table table = new Table();
int number;
MyThread_2(Table table, int number){
[Link] = table;
[Link] = number;
}
public void run() {
[Link](number);
}
}
public class ThreadSynchronizationExample {
public static void main(String[] args) {
Table table = new Table();
MyThread_1 thread_1 = new MyThread_1(table, 5);
MyThread_2 thread_2 = new MyThread_2(table, 10);
thread_1.start();
thread_2.start();
}
}
Synchronized block
The synchronized block is used when we want to synchronize only a specific sequence of lines in a method. For
example, let's consider a method with 20 lines of code where we want to synchronize only a sequence of 5 lines
code, we use the synchronized block.
The complete code of a method may be written inside the synchronized block, where it works similarly to the
synchronized method.

Syntax
synchronized(object){
block code
}
Example
import [Link].*;
class NameList {
String name = "";
public int count = 0;
public void addName(String name, List<String> namesList){
synchronized(this){
[Link] = name;
count++;
}
[Link](name);
}

public int getCount(){


return count;
} }
public class SynchronizedBlockExample {
public static void main (String[] args)
{
NameList namesList_1 = new NameList();
NameList namesList_2 = new NameList();
List<String> list = new ArrayList<String>();
namesList_1.addName("Rama", list);
namesList_2.addName("Seetha", list);
[Link]("Thread1: " + namesList_1.name + ", " +
namesList_1.getCount() + "\n");
[Link]("Thread2: " + namesList_2.name + ", " +
namesList_2.getCount() + "\n");
} }
Static Synchronization
If you make any static method as synchronized, the lock will be on the class not on object.

Problem without static synchronization


Suppose there are two objects of a shared class(e.g. Table) named object1 and [Link] case of synchronized
method and synchronized block there cannot be interference between t1 and t2 or t3 and t4 because t1 and t2
both refers to a common object that have a single [Link] there can be interference between t1 and t3 or t2 and
t4 because t1 acquires another lock and t3 acquires another lock.I want no interference between t1 and t3 or t2
and [Link] synchronization solves this problem.
class Table{
synchronized static void printTable(int n){
for(int i=1;i<=10;i++){
[Link](n*i);
try{
[Link](400);
}catch(Exception e){}
} }
}
class MyThread1 extends Thread{
public void run(){
[Link](1);
}
}
class MyThread2 extends Thread{
public void run(){
[Link](10);
}
}

class MyThread3 extends Thread{


public void run(){
[Link](100);
}
}
class MyThread4 extends Thread{
public void run(){
[Link](1000);
} }
public class TestSynchronization4{
public static void main(String t[]){
MyThread1 t1=new MyThread1();
MyThread2 t2=new MyThread2();
MyThread3 t3=new MyThread3();
MyThread4 t4=new MyThread4();
[Link]();
[Link]();
[Link]();
[Link](); } }

Deadlock in java
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.
Example

public class TestDeadlockExample1 {


public static void main(String[] args) {
final String resource1 = "ratan jaiswal";
final String resource2 = "vimal jaiswal";
// t1 tries to lock resource1 then resource2
Thread t1 = new Thread() {
public void run() {
synchronized (resource1) {
[Link]("Thread 1: locked resource 1");
try { [Link](100);} catch (Exception e) {}
synchronized (resource2) {
[Link]("Thread 1: locked resource 2");
} } } };
// t2 tries to lock resource2 then resource1
Thread t2 = new Thread() {
public void run() {
synchronized (resource2) {
[Link]("Thread 2: locked resource 2");
try { [Link](100);} catch (Exception e) {}
synchronized (resource1) {
[Link]("Thread 2: locked resource 1");
} } } };

[Link]();
[Link]();
}
}
Output: Thread 1: locked resource 1
Thread 2: locked resource 2
Java Inter Thread Communication
Inter thread communication is the concept where two or more threads communicate to solve the problem of
polling. In java, polling is the situation to check some condition repeatedly, to take appropriate action, once the
condition is true. That means, in inter-thread communication, a thread waits until a condition becomes true such
that other threads can execute its task. The inter-thread communication allows the synchronized threads to
communicate with each other.
Java provides the following methods to achieve inter thread communication.
 wait( )
 notify( )
 notifyAll( )

1) 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.

2) 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()
Difference between wait and sleep

Example of inter thread communication in java


class Customer{
int amount=10000;
synchronized void withdraw(int amount){
[Link]("going to withdraw...");
if([Link]<amount){
[Link]("Less balance; waiting for deposit...");
try{wait();}catch(Exception e){}
}
[Link]-=amount;
[Link]("withdraw completed...");
}
synchronized void deposit(int amount){
[Link]("going to deposit...");
[Link]+=amount;
[Link]("deposit completed... ");
notify(); } }
class Test{
public static void main(String args[]){
final Customer c=new Customer();
new Thread(){
public void run(){[Link](15000);}
}.start();
new Thread(){
public void run(){[Link](10000);}
}.start(); }}
Output: going to withdraw...
Less balance; waiting for deposit...
going to deposit...
deposit completed...
withdraw completed

Calling notify( ) or notifyAll( ) does not actually give up a lock on a resource.


Let's look at an example problem of producer and consumer. The producer produces the item and the consumer
consumes the same. But here, the consumer can not consume until the producer produces the item, and
producer can not produce until the consumer consumes the item that already been produced. So here, the
consumer has to wait until the producer produces the item, and the producer also needs to wait until the
consumer consumes the same. Here we use the inter-thread communication to implement the producer and
consumer problem.
producer and consumer problem is as follows.
class ItemQueue {
int item;
boolean valueSet = false;
synchronized int getItem() {
while (!valueSet)
try {
wait();
} catch (InterruptedException e) {
[Link]("InterruptedException caught");
}
[Link]("Consummed:" + item);
valueSet = false;
try {
[Link](1000);
} catch (InterruptedException e) {
[Link]("InterruptedException caught");
} notify();
return item; }
synchronized void putItem(int item) {
while (valueSet)
try {
wait();
} catch (InterruptedException e) {
[Link]("InterruptedException caught");
}
[Link] = item;
valueSet = true;
[Link]("Produced: " + item);
try {
[Link](1000);
} catch (InterruptedException e) {
[Link]("InterruptedException caught");
}
notify();
} }
class Producer implements Runnable{
ItemQueue itemQueue;
Producer(ItemQueue itemQueue){
[Link] = itemQueue;
new Thread(this, "Producer").start(); }
public void run() {
int i = 0;
while(true) {
[Link](i++);
}
}
}
class Consumer implements Runnable{
ItemQueue itemQueue;
Consumer(ItemQueue itemQueue){
[Link] = itemQueue;
new Thread(this, "Consumer").start();
}
public void run() {
while(true) {
[Link]();
}
}
}
class ProducerConsumer{
public static void main(String args[]) {
ItemQueue itemQueue = new ItemQueue();
new Producer(itemQueue);
new Consumer(itemQueue);

}
}
All the methods wait( ), notify( ), and notifyAll( ) can be used only inside the synchronized methods only.
ThreadGroup
ThreadGroup in java can be defined as a collection of threads created to work as a unit, ThreadGroup in java is
generally used when there is a need to perform a combined operation on a group of threads; ThreadGroup offers
an efficient way to manage multiple threads.
Class Declaration
Following is the declaration for [Link] class –
public class ThreadGroup
extends Object
implements [Link]
Class constructors

[Link]. Constructor & Description


ThreadGroup(String name)
1
This constructs a new thread group.

ThreadGroup(ThreadGroup parent, String name)


2
This creates a new thread group.

Class methods

[Link]. Method & Description

int activeCount()
1
This method returns an estimate of the number of active threads in this thread group.

int activeGroupCount()
2
This method returns an estimate of the number of active groups in this thread group.

void checkAccess()
3 This method determines if the currently running thread has permission to modify this thread
group.

void destroy()
4
This method Destroys this thread group and all of its subgroups.

int enumerate(Thread[] list)


5 This method copies into the specified array every active thread in this thread group and its
subgroups.

int enumerate(Thread[] list, boolean recurse)


6
This method copies into the specified array every active thread in this thread group.

int enumerate(ThreadGroup[] list)


7 This method copies into the specified array references to every active subgroup in this thread
group.

int enumerate(ThreadGroup[] list, boolean recurse)


8 This method copies into the specified array references to every active subgroup in this thread
group.

int getMaxPriority()
9
This method returns the maximum priority of this thread group.
String getName()
10
This method returns the name of this thread group.

ThreadGroup getParent()
11
This method returns the parent of this thread group.

void interrupt()
12
This method interrupts all threads in this thread group.

boolean isDaemon()
13
This method Tests if this thread group is a daemon thread group.

boolean isDestroyed()
14
This method tests if this thread group has been destroyed.

void list()
15
This method prints information about this thread group to the standard output.

boolean parentOf(ThreadGroup g)
16 This method tests if this thread group is either the thread group argument or one of its
ancestor thread groups.

void setDaemon(boolean daemon)


17
This method changes the daemon status of this thread group.

void setMaxPriority(int pri)


18
This method sets the maximum priority of the group.

String toString()
19
This method returns a string representation of this Thread group.

void uncaughtException(Thread t, Throwable e)

20 This method called by the Java Virtual Machine when a thread in this thread group stops
because of an uncaught exception, and the thread does not have a specific
[Link] installed.

Example
package [Link];
import [Link].*;
class ThreadDemo extends Thread
{
ThreadDemo(String threadname, ThreadGroup thgrp)
{
super(thgrp, threadname);
start();
}
public void run()
{
// implement required logic inside run method
for (int i = 0; i < 2000; i++)
{
try
{
[Link](20);
}
catch (InterruptedException e)
{
[Link]("InterruptedException Exception encountered");
}
}
}
}
public class ThreadGroupDemo
{
public static void main(String args[])
{
// creating the thread group
ThreadGroup grp = new ThreadGroup("parent-thread");
// creating new thread and adding to thread group
ThreadDemo t1 = new ThreadDemo("first", grp);
[Link]("Starting first thread");
// creating another thread and adding to thread group
ThreadDemo t2 = new ThreadDemo("two", grp);
[Link]("Starting second thread");
// finding the number of active threads
[Link]("Number of active threads running in thread group: " +
[Link]());
}
}
Output:

You might also like