0% found this document useful (0 votes)
7 views40 pages

OOOpsunit 2

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)
7 views40 pages

OOOpsunit 2

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
You are on page 1/ 40

UNIT-2

What is exception handling?

Exception handling in Java allows developers to manage runtime errors effectively


by using mechanisms like try-catch block, finally block, throwing
Exceptions, Custom Exception handling, etc.
An Exception is an unwanted or unexpected event that occurs during the execution
of a program (i.e., at runtime) and disrupts the normal flow of the program’s
instructions. It occurs when something unexpected happens, like accessing an
invalid index, dividing by zero, or trying to open a file that does not exist.
Java Exception Hierarchy
All exception and error types are subclasses of the class Throwable,
which is the base class of the hierarchy. One branch is headed
by Exception. This class is used for exceptional conditions that user
programs should catch. NullPointerException is an example of such an
exception. Another branch, Error is used by the Java run-time
system(JVM) to indicate errors having to do with the run-time environment
itself(JRE). StackOverflowError is an example of such an error.
The hierarchy of Java Exception classes is given below:
Checked Exceptions (Compile-Time Exceptions)
Exception Class Description
IOException Input/output failure (e.g., file not found)
FileNotFoundException File doesn't exist when trying to open
SQLException Issues during database access
ClassNotFoundException Class not found while trying to load it dynamically
InterruptedException Thread interrupted while sleeping or waiting
ParseException Issues with parsing strings (e.g., date formats)
InstantiationException Object cannot be instantiated using newInstance()
NoSuchMethodException A requested method does not exist
InvocationTargetException Exception thrown by an invoked method via reflection
MalformedURLException Invalid URL format

Unchecked Exceptions (Runtime Exceptions)


Exception Class Description
NullPointerException Accessing method or field on a null object
ArrayIndexOutOfBoundsException Accessing an array index that doesn't exist
StringIndexOutOfBoundsException Indexing outside a string range
ArithmeticException Division by zero or invalid arithmetic operation
ClassCastException Improper casting of objects
NumberFormatException Invalid conversion from string to number
IllegalArgumentException Method received illegal argument
IllegalStateException Method invoked at inappropriate time
Input type doesn't match expected (e.g.,
InputMismatchException
Scanner)
UnsupportedOperationException Called method is not supported

Types of Java Exceptions


In Java, exceptions are categorized into two main types: checked exceptions and
unchecked exceptions. Additionally, there is a third category known as errors. Let's
delve into each of these types:
1. Checked Exception
2. Unchecked Exception
3. Error

Major Reasons Why an Exception Occurs


Exceptions can occur due to between several reasons, such as:
 Invalid user input
 Device failure
 Loss of network connection
 Physical limitations (out-of-disk memory)
 Code errors
 Out of bound
 Null reference
 Type mismatch
 Opening an unavailable file
 Database errors
 Arithmetic errors
Errors represent irrecoverable conditions such as Java virtual machine (JVM)
running out of memory, memory leaks, stack overflow errors, library incompatibility,
infinite recursion, etc. Errors are usually beyond the control of the programmer, and
we should not try to handle errors.
Difference Between Exception and Error
Aspect Error Exception

Exception indicates
An Error indicates a serious
conditions that a reasonable
problem that a reasonable
Definition application might try to catch
Aspect Error Exception

application should not try to


catch.

Caused by conditions in the


Caused by issues with the
program such as invalid input
JVM or hardware.
Cause or logic errors.

OutOfMemoryError IOException
Examples StackOverFlowError NullPointerException

Exceptions can be categorized in two ways:


1. Built-in Exceptions

 Checked Exception
 Unchecked Exception
2. User-Defined Exceptions
1. Built-in Exception
Build-in Exception are pre-defined exception classes provided by Java to handle
common errors during program execution.
1.1 Checked Exceptions
Checked exceptions are called compile-time exceptions because these exceptions
are checked at compile-time by the compiler. Examples of Checked Exception are
listed below:
1. ClassNotFoundException: Throws when the program tries to load a class at
runtime but the class is not found because it’sbelong not present in the correct
location or it is missing from the project.
2. InterruptedException: Thrown when a thread is paused and another thread
interrupts it.
3. IOException: Throws when input/output operation fails
4. InstantiationException: Thrown when the program tries to create an object of
a class but fails because the class is abstract, an interface, or has no default
constructor.
5. SQLException: Throws when there’s an error with the database.
6. FileNotFoundException: Thrown when the program tries to open a file that
doesn’t exist
1.2 Unchecked Exceptions
The unchecked exceptions are just opposite to the checked exceptions. The
compiler will not check these exceptions at compile time. In simple words, if a
program throws an unchecked exception, and even if we didn’t handle or declare it,
the program would not give a compilation error. Examples of Unchecked Exception
are listed below:
1. ArithmeticException: It is thrown when there’s an illegal math operation.
2. ClassCastException: It is thrown when you try to cast an object to a class it
does not belongThis to.
3. NullPointerException: It is thrown when you try to use a null object (e.g.
accessing its methods or fields)
4. ArrayIndexOutOfBoundsException: ThisThis occurs when we try to access
an array element with an invalid index.
5. ArrayStoreException: Thishandle happens when you store an object of the
wrong type in an array.
6. IllegalThreadStateException: It is thrown when a thread operation is not
allowed in its current state
User-Defined Exception
Sometimes, the built-in exceptions in Java are not able to describe a certain situation.
In such cases, users can also create exceptions, which are called “user-defined
Exceptions“.
Methods to Print the Exception Information
Method Description

Prints the full stack trace of the


exception, including the name,
message, and location of the
printStackTrace() error.

Prints exception information in


the format of the Name of the
toString() exception.

Prints the description of the


getMessage() exception.

JVM reaction to exception


When an exception occurs in a Java program, the Java Virtual Machine (JVM) takes the
following steps:
. Checks for a Matching Catch Block
 The JVM looks for a try-catch block that can handle the thrown exception.
 It starts with the method where the exception occurred and moves up the call stack
(the chain of method calls).
2. If No Catch Block Found
 If the JVM cannot find a suitable catch block:
o It terminates the thread where the exception occurred.
o It prints an exception stack trace to the console, showing:
 The type of exception (e.g., NullPointerException)
 A message (if any)
 The method call sequence that led to the error.
Difference Between Checked and Unchecked Exceptions
Feature Checked Exception Unchecked Exception

Behavi Checked exceptions are Unchecked exceptions are


our checked at compile time. checked at run time.
Feature Checked Exception Unchecked Exception

Base
Derived from Exception Derived from RuntimeException
class

External factors like file I/O and Programming bugs like logical
database connection cause the errors cause unchecked
Cause checked Exception. Exceptions.

Handlin Checked exceptions must be


g handled using a try-catch
No handling is required
Require block or must be declared using
ment the throws keyword

Exampl IOException, SQLException, Fil NullPointerException, ArrayIndexO


es eNotFoundException. utOfBoundsException.

Java try block


Java try block is used to enclose the code that might throw an exception. It
must be used within Java catch block
the method.
If an exception occurs at the particular statement in the try block, the rest of the block
code will not execute. So, it is recommended not to keep the code in try block that will
not throw an exception.
Java try block must be followed by either catch or finally block.
Syntax of Java try-catch
1. try{
2. //code that may throw an exception
3. }catch(Exception_class_Name ref){}
Syntax of try-finally block
1. try{
2. //code that may throw an exception
3. }finally{}
Java catch block

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.
finally Block
The finally Block is used to execute important code regardless of whether an
exception occurs or not.
Note: finally block is always executes after the try-catch block. It is also used for
resource cleanup.
try {
// Code that may throw an exception
} catch (ExceptionType e) {
// Code to handle the exception
}finally{
// cleanup code
}
Difference Between throw and throws in Java
The differences between throw and throws in Java are:
S. Key
No. Difference throw throws

The throws keyword is used


The throw keyword is used
in the function signature. It is
Point of inside a function. It is used
1. used when the function has
Usage when it is required to throw
some statements that can
an Exception logically.
lead to exceptions.

The throws keyword can be


used to declare multiple
The throw keyword is used
exceptions, separated by a
Exceptions to throw an exception
2. comma. Whichever exception
Thrown explicitly. It can throw only
occurs, if matched with the
one exception at a time.
declared ones, is thrown
automatically then.

Syntax of throw keyword Syntax of throws keyword


includes the instance of the includes the class names of
Exception to be thrown. the Exceptions to be thrown.
3. Syntax
Syntax wise throw keyword Syntax wise throws keyword
is followed by the instance is followed by exception class
variable. names.

throw keyword cannot


propagate checked
Propagation exceptions. It is only used throws keyword is used to
4. of to propagate the propagate the checked
Exceptions unchecked Exceptions that Exceptions only.
are not checked using the
throws keyword.

ArithmeticException Example
public class ArithmeticExceptionDemo {
public static void main(String[] args) {
int a = 10;
int b = 0; // This will cause division by zero

try {
int result = a / b; // ArithmeticException occurs here
System.out.println("Result: " + result);
} catch (ArithmeticException e) {
System.out.println("Exception caught: " + e.getMessage());
} finally {
System.out.println("Finally block executed.");
}
}
}
Output:
Exception caught: / by zero
Finally block executed.

NullPointerException Example
public class NullPointerExceptionDemo {
public static void main(String[] args) {
String str = null; // str is not pointing to any object

try {
// This will throw NullPointerException
int length = str.length();
System.out.println("Length of the string: " + length);
} catch (NullPointerException e) {
System.out.println("Exception caught: " + e.getMessage());
} finally {
System.out.println("Finally block executed.");
}
}
}
Output:
Exception caught: Cannot invoke "String.length()" because "str" is null
Finally block executed.

(Array Index Out of Bound Example)


An "Array Index Out of Bounds" exception occurs in programming when you try to
access an element of an array using an index that is outside the valid range of
indices. Arrays are zero-indexed in most languages, so the valid indices are from 0
to array.length - 1.

public class ArrayIndexExample {


public static void main(String[] args) {
int[] arr = {10, 20, 30, 40, 50};

try {
// Trying to access an out-of-bounds index
System.out.println("Value at index 5: " + arr[5]);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Exception caught: " + e);
System.out.println("Please access a valid index (0 to " + (arr.length - 1) + ").");
}
System.out.println("Program continues after exception handling.");
}
}
Output:
Exception caught: java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for
length 5
Please access a valid index (0 to 4).
Program continues after exception handling.

(StringIndexOutOfBoundsException Example)

In Java, a StringIndexOutOfBoundsException occurs when you try to access a character in a


String using an index that is either negative or greater than or equal to the length of the string.

public class StringIndexExample {

public static void main(String[] args) {

String str = "Hello";

try {

// Trying to access index 5 (which is invalid since valid indices are 0 to 4)

char ch = str.charAt(5);

System.out.println("Character at index 5: " + ch);

} catch (StringIndexOutOfBoundsException e) {

System.out.println("Exception caught: " + e);

System.out.println("Valid indices are from 0 to " + (str.length() - 1));

System.out.println("Program continues after exception handling.");

}
OUTPUT:
Exception caught: java.lang.StringIndexOutOfBoundsException: String index out of
range: 5
Valid indices are from 0 to 4
Program continues after exception handling.
What is ClassNotFoundException in Java?
ClassNotFoundException is a checked exception in Java that occurs when an
application tries to load a class at runtime using:
 Class.forName("...")
 ClassLoader.loadClass("...")
...and the class cannot be found in the classpath.
Key Points:

 Happens at runtime, not during compilation.


 Common in JDBC, reflection, or dynamic loading scenarios.
 It must be handled using try-catch or declared with throws.

public class ClassNotFoundExample {

public static void main(String[] args) {

try {

// Trying to load a class that does not exist

Class.forName("com.example.NonExistentClass");

} catch (ClassNotFoundException e) {

System.out.println("Exception caught: " + e);

System.out.println("The specified class was not found in the classpath.");

System.out.println("Program continues after handling ClassNotFoundException.");

Output:
Exception caught: java.lang.ClassNotFoundException: com.example.NonExistentClass
The specified class was not found in the classpath.
Program continues after handling ClassNotFoundException.

What is ClassCastException in Java?


ClassCastException is a runtime exception that occurs when you try to cast an
object to a subclass or unrelated class that it is not an instance of.
Key Points:

 It’s an unchecked exception (does not need to be declared or caught).


 Occurs when using explicit type casting with objects.
 Detected only at runtime, not during compilation.

public class ClassCastExample {

public static void main(String[] args) {

Object obj = new String("Hello");

try {

// Attempting to cast a String to an Integer (not allowed)

Integer num = (Integer) obj;

System.out.println("Integer value: " + num);

} catch (ClassCastException e) {

System.out.println("Exception caught: " + e);

System.out.println("Cannot cast String to Integer.");

System.out.println("Program continues after exception handling.");

}
}

Output:
Exception caught: java.lang.ClassCastException: java.lang.String cannot be cast to
java.lang.Integer
Cannot cast String to Integer.
Program continues after exception handling.

What is NumberFormatException in Java?


NumberFormatException is a runtime exception in Java that occurs when you try to
convert a string into a number, but the string is not a valid format for that type.
Key Points:

 It is an unchecked exception (subclass of IllegalArgumentException).


 Common when using methods like Integer.parseInt(), Double.parseDouble(), etc.
 Happens when the string contains non-numeric characters, empty strings, or invalid
number formats.

public class NumberFormatExample {

public static void main(String[] args) {

String input = "123abc"; // Invalid number format

try {

int number = Integer.parseInt(input); // Will throw exception

System.out.println("Parsed number: " + number);

} catch (NumberFormatException e) {

System.out.println("Exception caught: " + e);

System.out.println("Invalid number format: '" + input + "'");

System.out.println("Program continues after exception handling.");

OUTPUT:
Exception caught: java.lang.NumberFormatException: For input string: "123abc"
Invalid number format: '123abc'
Program continues after exception handling.

What is IllegalArgumentException in Java?


IllegalArgumentException is a runtime exception thrown to indicate that a method
has been passed an illegal or inappropriate argument.
Key Points:

 It is an unchecked exception (extends RuntimeException).


 Often thrown manually by developers to enforce input validation.
 Helps defend against invalid method arguments.

public class IllegalArgumentExample {

// Method that throws IllegalArgumentException for invalid input

public static void setAge(int age) {

if (age < 0) {

throw new IllegalArgumentException("Age cannot be negative: " + age);

System.out.println("Age is set to: " + age);

public static void main(String[] args) {

try {

setAge(-5); // Invalid argument

} catch (IllegalArgumentException e) {

System.out.println("Exception caught: " + e);

System.out.println("Program continues after exception handling.");

OUTPUT:
Exception caught: java.lang.IllegalArgumentException: Age cannot be negative: -5
Program continues after exception handling.
Java Program Demonstrating throw and throws

public class ThrowThrowsExample {

// Method declares it might throw an exception


public static void checkAge(int age) throws IllegalArgumentException {
if (age < 18) {
// throw used to explicitly throw an exception
throw new IllegalArgumentException("Access denied - You must be 18 or
older.");
} else {
System.out.println("Access granted - You are old enough!");
}
}

public static void main(String[] args) {


try {
checkAge(16); // This will trigger the exception
} catch (IllegalArgumentException e) {
System.out.println("Exception caught: " + e.getMessage());
}

System.out.println("Program continues after exception handling.");


}
}
OUTPUT:
Exception caught: Access denied - You must be 18 or older.
Program continues after exception handling.

Scenario:

You are developing a banking login system where a user is allowed to enter their PIN only 3
times. If the user fails to enter the correct PIN after 3 attempts, the system should throw a
custom exception called TooManyAttemptsException and lock the account.

Question:

Write a Java program that simulates a simple PIN verification system. The correct PIN is 1234. The
user is allowed a maximum of 3 attempts to enter the correct PIN.
If the user fails all 3 times, throw a custom exception TooManyAttemptsException with an
appropriate message.
Catch and handle the exception in the main method and display the error message

Java Program: PIN Verification with Custom Exception.

import java.util.Scanner;
// Custom exception class

class TooManyAttemptsException extends Exception {

public TooManyAttemptsException(String message) {

super(message);

public class PinVerification {

private static final int CORRECT_PIN = 1234;

private static final int MAX_ATTEMPTS = 3;

public static void verifyPin() throws TooManyAttemptsException {

Scanner scanner = new Scanner(System.in);

int attempts = 0;

while (attempts < MAX_ATTEMPTS) {

System.out.print("Enter your 4-digit PIN: ");

int inputPin = scanner.nextInt();

if (inputPin == CORRECT_PIN) {

System.out.println("PIN verified successfully! Access granted.");

return;

} else {

attempts++;
System.out.println("Incorrect PIN. Attempt " + attempts + " of " + MAX_ATTEMPTS);

// If all attempts fail

throw new TooManyAttemptsException("Too many incorrect attempts. Your account is locked.");

public static void main(String[] args) {

try {

verifyPin();

} catch (TooManyAttemptsException e) {

System.out.println("Exception caught: " + e.getMessage());

System.out.println("Program ends.");

Output:
Enter your 4-digit PIN: 1111
Incorrect PIN. Attempt 1 of 3
Enter your 4-digit PIN: 2222
Incorrect PIN. Attempt 2 of 3
Enter your 4-digit PIN: 3333
Incorrect PIN. Attempt 3 of 3
Exception caught: Too many incorrect attempts. Your account is locked.
Program ends.

Scenario:
You are building a system for a library that allows users to check out books by entering their
library card number. The library card number must be a 6-digit numeric value. Users will
input their card numbers as strings, and the system must validate the format of the card
number.

If a user enters a card number that doesn't match the expected 6-digit numeric format, the
system should throw a NumberFormatException (which is a subclass of
InputMismatchException) and notify the user that the card number is invalid.

Java Program: Library Card Number Validation

import java.util.Scanner;

public class LibraryCardValidator {

// Method to validate a 6-digit numeric card number

public static void validateCardNumber(String input) throws NumberFormatException {

// Check if the input is exactly 6 digits and numeric

if (!input.matches("\\d{6}")) {

throw new NumberFormatException("Invalid library card number. Must be exactly 6


digits.");

System.out.println("Library card number " + input + " is valid. Access granted.");

public static void main(String[] args) {

Scanner scanner = new Scanner(System.in);

System.out.print("Enter your 6-digit library card number: ");

String cardNumber = scanner.nextLine();


try {

validateCardNumber(cardNumber);

} catch (NumberFormatException e) {

System.out.println("Exception caught: " + e.getMessage());

System.out.println("Program ends.");

OUTPUT:
Enter your 6-digit library card number: 123456
Library card number 123456 is valid. Access granted.
Program ends.
Enter your 6-digit library card number: ab123
Exception caught: Invalid library card number. Must be exactly 6 digits.
Program ends.

Scenario:

You are developing a simple ATM-like application that allows users to withdraw money from their
account. The application asks the user to enter the amount to withdraw, which must be an integer
value (e.g., 100, 500, 1000).

However, if the user accidentally enters a non-integer input such as text ("abc") or a decimal
number ("100.50"), the program should catch an InputMismatchException, inform the user of
the mistake, and allow them to try again.

Java Program: ATM Withdrawal with Input Validation

import java.util.Scanner;

import java.util.InputMismatchException;

public class ATMWithdrawal {


public static void main(String[] args) {

Scanner scanner = new Scanner(System.in);

int amount = 0;

boolean validInput = false;

System.out.println("=== Welcome to the ATM ===");

// Loop until valid integer input is received

while (!validInput) {

System.out.print("Enter the amount you wish to withdraw (integer only): ");

try {

amount = scanner.nextInt(); // May throw InputMismatchException

if (amount <= 0) {

System.out.println("Amount must be greater than zero.");

} else {

validInput = true; // Exit loop if input is valid

} catch (InputMismatchException e) {

System.out.println("Invalid input! Please enter a whole number (e.g., 100, 500).");

scanner.nextLine(); // Clear the invalid input

System.out.println("You have successfully withdrawn: ₹" + amount);


System.out.println("=== Thank you for using the ATM ===");

OutPut:

=== Welcome to the ATM ===

Enter the amount you wish to withdraw (integer only): abc


Invalid input! Please enter a whole number (e.g., 100, 500).
Enter the amount you wish to withdraw (integer only): 100.50
Invalid input! Please enter a whole number (e.g., 100, 500).
Enter the amount you wish to withdraw (integer only): 500
You have successfully withdrawn: ₹500
=== Thank you for using the ATM ===

Input/output Basics: Byte Stream and Character Stream in java


Byte Stream
Byte streams in Java are used to perform input and output of binary data. They read and
write data one byte at a time and are suitable for handling files like images, audio, and
video. The base classes are InputStream and OutputStream. Since byte streams deal with
raw bytes, they do not support character encoding.
Examples: FileInputStream, FileOutputStream

import java.io.*;

public class ByteStreamExample {

public static void main(String[] args) throws IOException {

FileInputStream fis = new FileInputStream("input.bin");

FileOutputStream fos = new FileOutputStream("output.bin");

int data;

while ((data = fis.read()) != -1) {

fos.write(data);

fis.close();
fos.close();

}
OUTPUT:

The output is not printed to the console, and there is no visible output in the terminal or
console.

✅ The result is:

A new file named output.bin is created, and its content is an exact byte-for-byte copy
of input.bin.

Example:

If input.bin contains:

 Binary data from an image, a video, or even text — e.g., [01001000 01001001]
(binary for "HI")

Then output.bin will contain the same binary data, and both files will be identical in size
and content.

Character Stream
Character streams are designed for handling textual data. They read and write characters (2
bytes each) and support Unicode, making them ideal for reading and writing text files. The
base classes are Reader and Writer, which handle character encoding internally.

Examples: FileReader, FileWriter

import java.io.*;

public class CharacterStreamExample {

public static void main(String[] args) throws IOException {

FileReader fr = new FileReader("input.txt");

FileWriter fw = new FileWriter("output.txt");

int ch;

while ((ch = fr.read()) != -1) {

fw.write(ch);
}

fr.close();

fw.close();

OUTPUT:

 The program does not print anything to the console.


 Instead, it creates or overwrites a file named output.txt with the same text content
as input.txt.

Example:

Hello, Java!

This is a text file.

Then after the program runs, output.txt will contain:

Hello, Java!

This is a text file.

Why can we read a .txt file using a Byte Stream in Java?


Even though character streams (Reader, Writer) are designed specifically for text data,
you can still read a .txt file using byte streams (InputStream, OutputStream) because
everything is stored as bytes in a file — even text.

Here’s Why It Works:

 A text file stores characters using a specific encoding (e.g., UTF-8, ASCII).
 Byte streams read raw bytes from the file.
 If you use a byte stream to read a text file, you are just reading the encoded bytes.
 However, you must manually decode those bytes to characters if you want to display
or process the text correctly.

Why It’s Not Ideal:

 Byte streams don't handle character encoding.


 If you read a .txt file with a byte stream and just cast bytes to char, it may lead to
incorrect or garbled output, especially with non-ASCII characters (like é, ç, ह).

Byte Stream vs. Character Stream


Feature Byte Stream Character Stream
Purpose Handles binary data Handles text (character)
data
Base Classes InputStream, Reader, Writer
OutputStream
Data Unit 1 byte (8 bits) 2 bytes (16-bit Unicode
characters)
File Type Binary files (images, audio, Text files (.txt, .csv, .xml,
etc.) etc.)
Encoding Not aware of character Aware of character encoding
encoding (e.g., UTF-8)
Performance Faster for binary data Better suited for text
processing
Examples FileInputStream, FileReader, FileWriter
FileOutputStream
Use Case Reading/writing images, Reading/writing text
PDFs, etc. documents

MULTITHREADING

THREAD
In Java, a thread is a lightweight subprocess — the smallest unit of execution. Java allows
multiple threads to run concurrently, enabling multitasking within a program.

Why Use Threads?

 To perform multiple tasks at once (e.g., loading UI while downloading data).


 To improve performance in CPU-bound or I/O-bound tasks.
 For concurrent or asynchronous programming.

MULTITHREADING
Multithreading means running two or more threads (parts of a program) simultaneously.
Each thread runs independently, but shares the same memory space.
Ways to Create a Thread

1. Extending the Thread class


class MyThread extends Thread {
public void run() {
System.out.println("Thread is running");
}

public static void main(String[] args) {


MyThread t = new MyThread();
t.start(); // starts a new thread
}
}
Output:
Thread is running
2. Implement the Runnable interface
class MyRunnable implements Runnable {
public void run() {
System.out.println("Runnable thread: " + Thread.currentThread().getName());
}

public static void main(String[] args) {


Thread t1 = new Thread(new MyRunnable());
Thread t2 = new Thread(new MyRunnable());
t1.start();
t2.start();
}
}
Output:
Runnable thread: Thread-0
Runnable thread: Thread-1

3..Using Lambda (Java 8+)


public class LambdaThread {
public static void main(String[] args) {
Thread t = new Thread(() -> {
System.out.println("Thread using lambda is running");
});
t.start();
}
}
Output:
Thread using lambda is running

Common Methods in Java Multithreading

Method Description
start() Starts the thread and calls the run() method asynchronously.
run() Contains the code that defines the thread’s task.
sleep(long millis) Pauses the thread for the specified number of milliseconds.

join()
Causes the current thread to wait until the thread on which join()
was called finishes.
yield()
Suggests that the thread scheduler give other threads a chance to run
(a hint, not guaranteed).
isAlive() Checks if the thread is still running (has not finished execution).
setPriority(int p)
Sets the thread’s priority (ranges from Thread.MIN_PRIORITY = 1 to
Thread.MAX_PRIORITY = 10).
getPriority() Returns the thread’s current priority.
Method Description
getName() Returns the thread’s name.
setName(String
name) Sets the thread’s name.

interrupt()
Interrupts a thread, setting its interrupted status; can be used to stop a
sleeping/waiting thread.
isInterrupted()
Tests if the thread has been interrupted (does not clear the
interrupted status).
currentThread() Returns a reference to the currently executing thread.
setPriority() Method in Java
This method sets the priority level of a thread. Thread priority helps the thread scheduler decide
which thread to run first, though it's not guaranteed and depends on the JVM and OS.
Constant Value Description
Thread.MIN_PRIORITY 1 Lowest priority
Thread.NORM_PRIORITY 5 Default (normal)
Thread.MAX_PRIORITY 10 Highest priority

Life Cycle of a Thread in Java

The life cycle of a thread in Java refers to the various states of a thread goes through. For
example, a thread is born, started, runs, and then dies. Thread class defines the life cycle
and various states of a thread.

States of a Thread Life Cycle in Java

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.
 Runnable − After a newly born thread is started, the thread becomes runnable. A
thread in this state is considered to be executing its task.
 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.
 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.
 Terminated (Dead) − A runnable thread enters the terminated state when it
completes its task or otherwise terminates.

Example 1

In this example,we're using sleep() method to introduce some delay in


processing and to show case the parallel processing using threads. We're
creating two threads by extending the Thread class. We're printing each state of
the thread. When a thread object is created, its state is NEW; when start()
method is called, state is START; when run() method is called, state is
RUNNING; in case sleep() is called, then thread goes to WAITING state; When a
thread finished the processing the run() method, it went to DEAD state.

class ThreadDemo extends Thread {


private Thread t;
private String threadName;
ThreadDemo( String name) {
threadName = name;
System.out.println("Thread: " + threadName + ", " + "State: New");
}
public void run() {
System.out.println("Thread: " + threadName + ", " + "State: Running");
try {
for(int i = 4; i > 0; i--) {
System.out.println("Thread: " + threadName + ", " + i);
// Let the thread sleep for a while.
System.out.println("Thread: " + threadName + ", " + "State: Waiting");
Thread.sleep(50);
}
} catch (InterruptedException e) {
System.out.println("Thread " + threadName + " interrupted.");
}
System.out.println("Thread: " + threadName + ", " + "State: Dead");
}

public void start () {


System.out.println("Thread: " + threadName + ", " + "State: Start");
if (t == null) {
t = new Thread (this, threadName);
t.start ();
}
}
}
public class Main {
public static void main(String args[]) {
ThreadDemo thread1 = new ThreadDemo( "Thread-1");
ThreadDemo thread2 = new ThreadDemo( "Thread-2");
thread1.start();
thread2.start();
}
}
Output:
Thread: Thread-1, State: New
Thread: Thread-2, State: New
Thread: Thread-1, State: Start
Thread: Thread-2, State: Start
Thread: Thread-1, State: Running
Thread: Thread-2, State: Running
Thread: Thread-1, 4
Thread: Thread-2, 4
Thread: Thread-2, State: Waiting
Thread: Thread-1, State: Waiting
Thread: Thread-2, 3
Thread: Thread-2, State: Waiting
Thread: Thread-1, 3
Thread: Thread-1, State: Waiting
Thread: Thread-1, 2
Thread: Thread-1, State: Waiting
Thread: Thread-2, 2
Thread: Thread-2, State: Waiting
Thread: Thread-1, 1
Thread: Thread-1, State: Waiting
Thread: Thread-2, 1
Thread: Thread-2, State: Waiting
Thread: Thread-2, State: Dead
Thread: Thread-1, State: Dead

Write a java program using setName() and getName() method to create threads.
class MyThread extends Thread {
public void run() {
System.out.println("Thread is running: " + getName());
}
}

public class ThreadNameExample {


public static void main(String[] args) {
// Create two threads
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();

// Set custom names


t1.setName("Worker-Thread-1");
t2.setName("Worker-Thread-2");

// Print thread names before starting


System.out.println("Thread 1 name: " + t1.getName());
System.out.println("Thread 2 name: " + t2.getName());

// Start the threads


t1.start();
t2.start();

// Print main thread name


System.out.println("Main thread: " + Thread.currentThread().getName());
}
}
Ouput:
Thread 1 name: Worker-Thread-1
Thread 2 name: Worker-Thread-2
Main thread: main
Thread is running: Worker-Thread-1
Thread is running: Worker-Thread-2

Write a java program using getName(), setName() and setPriority(), getPriority() in


multithreading.
class MyRunnable implements Runnable {
public void run() {
// Get the current thread and print its name and priority
Thread current = Thread.currentThread();
System.out.println("Thread Name: " + current.getName());
System.out.println("Thread Priority: " + current.getPriority());
}
}

public class ThreadInfoExample {


public static void main(String[] args) {
// Create Runnable object
MyRunnable task = new MyRunnable();

// Create two threads


Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
// Set thread names
t1.setName("HighPriorityThread");
t2.setName("LowPriorityThread");

// Set thread priorities


t1.setPriority(Thread.MAX_PRIORITY); // 10
t2.setPriority(Thread.MIN_PRIORITY); // 1

// Print names and priorities before starting


System.out.println("Before start:");
System.out.println(t1.getName() + " Priority: " + t1.getPriority());
System.out.println(t2.getName() + " Priority: " + t2.getPriority());

// Start threads
t1.start();
t2.start();
}
}
Output:
Before start:
HighPriorityThread Priority: 10
LowPriorityThread Priority: 1
Thread Name: HighPriorityThread
Thread Priority: 10
Thread Name: LowPriorityThread
Thread Priority: 1

⚠ Note: The order of thread execution is not guaranteed — even though one thread has a
higher priority, the actual scheduling depends on the JVM and OS.

write a java program using sleep method in multithreading

class MyThread extends Thread {


public void run() {
for (int i = 1; i <= 5; i++) {
System.out.println(getName() + " - Count: " + i);
try {
Thread.sleep(1000); // Sleep for 1 second (1000 milliseconds)
} catch (InterruptedException e) {
System.out.println(getName() + " was interrupted");
}
}
}
}

public class SleepExample {


public static void main(String[] args) {
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();

t1.setName("Thread-1");
t2.setName("Thread-2");

t1.start();
t2.start();
}
}
Output:
Thread-1 - Count: 1
Thread-2 - Count: 1
Thread-1 - Count: 2
Thread-2 - Count: 2
Thread-1 - Count: 3
Thread-2 - Count: 3
Thread-1 - Count: 4
Thread-2 - Count: 4
Thread-1 - Count: 5
Thread-2 - Count: 5

⏱ The threads will print their messages every second, running concurrently.

What is Synchronizing Thread in Java?


Synchronizing a thread in Java means controlling the access of multiple threads to shared
resources (like variables, objects, or files) so that only one thread can use the resource at a
time.

Why Synchronization?
In multithreading, multiple threads may try to access and modify the same resource
simultaneously, leading to problems like:
 Inconsistent data
 Race conditions
 Unexpected behavior

To prevent this, Java provides synchronization to lock access to shared resources.

Thread Synchronization Example

class Counter {

private int count = 0;


// Synchronized method to prevent race condition

public synchronized void increment(String threadName) {

for (int i = 0; i < 5; i++) {

count++;

System.out.println(threadName + " incremented count to " + count);

try {

Thread.sleep(100); // simulate some delay

} catch (InterruptedException e) {

System.out.println(threadName + " was interrupted.");

public int getCount() {

return count;

class Worker extends Thread {

private Counter counter;

public Worker(Counter counter, String name) {

super(name);

this.counter = counter;
}

public void run() {

counter.increment(getName());

public class SyncDemo {

public static void main(String[] args) {

Counter sharedCounter = new Counter();

Worker t1 = new Worker(sharedCounter, "Thread-A");

Worker t2 = new Worker(sharedCounter, "Thread-B");

t1.start();

t2.start();

OUTPUT:

Thread-A incremented count to 1


Thread-A incremented count to 2
Thread-A incremented count to 3
Thread-A incremented count to 4
Thread-A incremented count to 5
Thread-B incremented count to 6
Thread-B incremented count to 7
Thread-B incremented count to 8
Thread-B incremented count to 9
Thread-B incremented count to 10

Java Program: Simple Thread Synchronization Example


class Printer {

// synchronized method to prevent overlapping output

public synchronized void printMessage(String message) {

System.out.print("[ " + message);

try {

Thread.sleep(500); // simulate delay

} catch (InterruptedException e) {

System.out.println("Interrupted");

System.out.println(" ]");

class MyThread extends Thread {

Printer printer;

String message;

MyThread(Printer printer, String message) {

this.printer = printer;

this.message = message;

public void run() {

printer.printMessage(message);

}
}

public class SimpleSyncExample {

public static void main(String[] args) {

Printer sharedPrinter = new Printer();

MyThread t1 = new MyThread(sharedPrinter, "Hello");

MyThread t2 = new MyThread(sharedPrinter, "World");

t1.start();

t2.start();

}
OUTPUT:

[ Hello ]

[ World ]

Scenario-Based Multithreading Question

Question:

You're building a Java application that simulates a ticket booking system for a theater. There
are only 10 tickets available. Multiple users are trying to book tickets at the same time
through different threads.

Write a Java program using multithreading to handle this scenario safely. Ensure that:

 No ticket is overbooked
 The ticket count is updated correctly
 The program prevents race conditions

Requirements:

 Use Thread or Runnable to simulate users trying to book.


 Use synchronization where necessary.
 Display the thread name and booking result.

Java Program: Multithreaded Ticket Booking System

class TicketBookingSystem {

private int ticketsAvailable = 10;

// Synchronized method to prevent race conditions

public synchronized void bookTicket(String userName, int numberOfTickets) {

if (numberOfTickets <= ticketsAvailable) {

System.out.println(userName + " booked " + numberOfTickets + " ticket(s) successfully.");

ticketsAvailable -= numberOfTickets;

System.out.println("Tickets remaining: " + ticketsAvailable);

} else {

System.out.println(userName + " tried to book " + numberOfTickets + " ticket(s), but only " +
ticketsAvailable + " are available. Booking failed.");

class User extends Thread {

private TicketBookingSystem bookingSystem;

private int ticketsToBook;

public User(TicketBookingSystem bookingSystem, String name, int ticketsToBook) {

super(name); // sets thread name

this.bookingSystem = bookingSystem;

this.ticketsToBook = ticketsToBook;
}

public void run() {

bookingSystem.bookTicket(getName(), ticketsToBook);

public class TicketBookingApp {

public static void main(String[] args) {

TicketBookingSystem bookingSystem = new TicketBookingSystem();

// Simulate multiple users trying to book tickets

User user1 = new User(bookingSystem, "Alice", 4);

User user2 = new User(bookingSystem, "Bob", 5);

User user3 = new User(bookingSystem, "Charlie", 3);

user1.start();

user2.start();

user3.start();

Output:

Alice booked 4 ticket(s) successfully.

Tickets remaining: 6

Bob booked 5 ticket(s) successfully.


Tickets remaining: 1

Charlie tried to book 3 ticket(s), but only 1 are available. Booking failed.

Thread Safety:

 The bookTicket() method is marked synchronized to ensure that only one thread
can access it at a time, preventing race conditions.

Thread communication in Java


Thread communication in Java refers to the coordination between multiple threads, typically
to ensure they work together efficiently by sharing resources or passing information. Java
provides several mechanisms for thread communication, with the most classic being the
wait(), notify(), and notifyAll() methods from the Object class.
These methods are used when threads share a common resource and need to wait for some
condition to be met before continuing execution.
Methods for Thread Communication
 wait() – causes the current thread to wait until another thread invokes notify() or
notifyAll() on the same object.
 notify() – wakes up a single thread that is waiting on the object's monitor.
 notifyAll() – wakes up all the threads that are waiting on the object's monitor.

These must be called from synchronized context (i.e., inside a synchronized block or
method)

EXAMPLE:
class Customer {
int amount = 10000;

synchronized void withdraw(int amount) {


System.out.println("Going to withdraw...");

if (this.amount < amount) {


System.out.println("Less balance; waiting for deposit...");
try {
wait(); // waits until deposit is made
} catch (Exception e) {
System.out.println(e);
}
}

this.amount -= amount;
System.out.println("Withdraw completed. Remaining balance: " + this.amount);
}

synchronized void deposit(int amount) {


System.out.println("Going to deposit...");
this.amount += amount;
System.out.println("Deposit completed. Current balance: " + this.amount);
notify(); // notifies the waiting thread
}
}

public class Main {


public static void main(String[] args) {
final Customer c = new Customer();

new Thread() {
public void run() {
c.withdraw(15000); // withdraw more than current balance
}
}.start();

new Thread() {
public void run() {
try {
Thread.sleep(2000); // wait for a moment before depositing
} catch (InterruptedException e) {
System.out.println(e);
}
c.deposit(10000); // deposit enough to allow withdrawal
}
}.start();
}
}
OUTPUT
Going to withdraw...
Less balance; waiting for deposit...
Going to deposit...
Deposit completed. Current balance: 20000
Withdraw completed. Remaining balance: 5000

USING notifyAll() method in program

class Customer {
int amount = 10000;

synchronized void withdraw(int amount) {


System.out.println(Thread.currentThread().getName() + " wants to withdraw...");

while (this.amount < amount) {


System.out.println(Thread.currentThread().getName() + " waiting due to low
balance...");
try {
wait(); // waits until deposit is made
} catch (Exception e) {
System.out.println(e);
}
}

this.amount -= amount;
System.out.println(Thread.currentThread().getName() + " completed withdrawal.
Remaining: " + this.amount);
}

synchronized void deposit(int amount) {


System.out.println(Thread.currentThread().getName() + " is depositing...");
this.amount += amount;
System.out.println(Thread.currentThread().getName() + " deposit complete. New
balance: " + this.amount);
notifyAll(); // wake up all waiting threads
}
}
public class Main {
public static void main(String[] args) {
final Customer c = new Customer();

// Multiple threads trying to withdraw


for (int i = 1; i <= 3; i++) {
final int threadNum = i;
Thread t = new Thread(new Runnable() {
public void run() {
c.withdraw(15000);
}
}, "Withdraw-Thread-" + threadNum);
t.start();
}

// Deposit thread
Thread depositThread = new Thread(new Runnable() {
public void run() {
try {
Thread.sleep(3000); // simulate delay before deposit
} catch (InterruptedException e) {
System.out.println(e);
}
c.deposit(50000); // deposit enough to wake all waiting threads
}
}, "Deposit-Thread");
depositThread.start();
}
}
OUTPUT:
Withdraw-Thread-1 wants to withdraw...
Withdraw-Thread-1 waiting due to low balance...
Withdraw-Thread-3 wants to withdraw...
Withdraw-Thread-3 waiting due to low balance...
Withdraw-Thread-2 wants to withdraw...
Withdraw-Thread-2 waiting due to low balance...
Deposit-Thread is depositing...
Deposit-Thread deposit complete. New balance: 60000
Withdraw-Thread-1 completed withdrawal. Remaining: 45000
Withdraw-Thread-2 completed withdrawal. Remaining: 30000
Withdraw-Thread-3 completed withdrawal. Remaining: 15000

You might also like