0% found this document useful (0 votes)
49 views17 pages

Java Unit 4

Uploaded by

pandu mandala
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)
49 views17 pages

Java Unit 4

Uploaded by

pandu mandala
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/ 17

JAVA UNIT – 4

1. Explain a. benefits of exception handling b. Termination and Presumptive models


Ans: a. Benefits of Exception Handling:Exception handling in programming languages like
Java provides several benefits:
( i )Improved Code Readability: Exception handling separates error-handling code from
regular code, making it easier to read and understand the main logic of the program.
Error Localization: Exceptions provide a mechanism for reporting and handling errors at the
point where they occur, allowing developers to pinpoint and address issues more effectively.
Program Robustness: By catching and handling exceptions, programs can recover gracefully
from errors and continue execution rather than crashing abruptly. This enhances the overall
robustness and reliability of the software.
Error Reporting: Exception handling allows developers to propagate error information up the
call stack, enabling higher-level components to handle errors appropriately or log them for
debugging purposes.
Resource Management: Exception handling can be used to ensure that resources such as file
handles, database connections, or network sockets are properly released, even in the error.
Custom Error Handling: Developers can define custom exception classes to represent specific
error conditions relevant to their application domain, allowing for more meaningful error
messages and tailored error-handling logic.
b. Termination and Presumptive Models: In the context of exception handling, termination
and presumptive models refer to different approaches for handling exceptions:
Termination Model:
• In the termination model, an exception is viewed as a fatal error that cannot be recovered
from. When an exception occurs, the program terminates execution immediately, and
control is transferred to the nearest exception handler (if one exists).
• This model is often used in environments where the consequences of an error are severe
or where recovery is not feasible, such as embedded systems or safety-critical
applications.
• Example languages that follow the termination model include C and C++ (when not
using exception handling constructs like try-catch).
Presumptive Model:
• In the presumptive model, exceptions are treated as exceptional but recoverable conditions.
When an exception occurs, the program continues execution, and control is transferred to
the nearest exception handler capable of handling the exception.
• This model allows programs to recover from errors and continue running, potentially
providing better user experience and system reliability.
• Java, C#, Python, and many other modern programming languages follow the presumptive
model by default, providing built-in exception handling mechanisms such as try-catch
blocks.

2. How Exception Terminates Java Program?Explain with an example.


Ans: In Java, exceptions can cause a program to terminate if they are not properly handled. When
an unhandled exception occurs, it propagates up the call stack until it reaches the top level of the
program, where it is typically caught by the default exception handler. If no appropriate exception
handler is found, the JVM terminates the program and prints a stack trace of the exception to the
console.
Here's an example to illustrate how an unhandled exception can terminate a Java program:
public class ExceptionTerminationExample {
public static void main(String[] args) {
// Attempting to access an element outside the bounds of the array
int[] numbers = {1, 2, 3};
System.out.println(numbers[3]); // this line throw an ArrayIndexOutOfBoundsException
}
}
In this example, the main method attempts to access the element at index 3 of the numbers array,
which is out of bounds since arrays in Java are zero-indexed. As a result, the statement
System.out.println(numbers[3]); throws an ArrayIndexOutOfBoundsException.
Since this exception is not caught within the main method or any method it calls, it propagates up
the call stack. Eventually, it reaches the top level of the program (the JVM), where it is not caught
by any user-defined exception handler.
When an exception is not caught by a user-defined handler, it is caught by the default exception
handler provided by the JVM. This default handler prints information about the exception,
including the exception type, message, and stack trace, to the console. After printing this
information, the JVM terminates the program.
When you run the above code, you will see output similar to the following:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds
for length 3 at ExceptionTerminationExample.main(ExceptionTerminationExample.java:6)
This output indicates that the program terminated due to an ArrayIndexOutOfBoundsException
occurring at line 6 of the ExceptionTerminationExample.java file.
3. Give the classification of exceptions.
Ans:

1. Checked Exceptions:

• Checked exceptions are the exceptions that are checked at compile-


time by the compiler.
• These exceptions are subclasses of Exception (but not
RuntimeException), and they are typically used to represent
anticipated error conditions that can occur during program
execution.
• Checked exceptions must be either caught (handled) using a try-
catch block or declared in the method's throws clause.
• Examples of checked exceptions include IOException,
FileNotFoundException, and SQLException.

2. Unchecked Exceptions (Runtime Exceptions):

• Unchecked exceptions are the exceptions that are not checked at


compile-time by the compiler.
• These exceptions are subclasses of RuntimeException, and they
typically represent programming errors or unexpected conditions
that can occur during runtime.
• Unlike checked exceptions, unchecked exceptions do not need to be
caught or declared explicitly in the throws clause.
• Examples of unchecked exceptions include NullPointerException,
ArrayIndexOutOfBoundsException, and IllegalArgumentException.

Additionally, there is a third category of exceptions called Errors, which are not
considered exceptions in the conventional sense. Errors represent serious, non-
recoverable problems that occur at runtime, such as OutOfMemoryError or
StackOverflowError. Unlike exceptions, errors are not normally caught or handled
by applications, as they typically indicate severe issues with the JVM or
underlying system.
4. Give the class hierarchy in java related to exception handling. Briefly explain each class?
Ans: Throwable:
• Throwable is the superclass of all classes representing errors and exceptions in Java.
• It has two direct subclasses: Error and Exception.
Error:
• Error is the superclass of all classes representing serious, non-recoverable problems that
occur at runtime.
• Errors typically indicate problems with the JVM or underlying system and are not normally
caught or handled by applications.
• Examples of Error subclasses include OutOfMemoryError and StackOverflowError.
Exception:
• Exception is the superclass of all classes representing exceptions that can be caught and
handled by applications.
• It encompasses both checked exceptions and unchecked exceptions (runtime exceptions).
• Examples of Exception subclasses include IOException, SQLException,
NullPointerException, and ArrayIndexOutOfBoundsException.
RuntimeException:
• RuntimeException is a subclass of Exception and represents exceptions that occur due to
programming errors or unexpected conditions during runtime.
• Unlike checked exceptions, runtime exceptions do not need to be caught or declared
explicitly in the throws clause.
• Examples of RuntimeException subclasses include NullPointerException,
ArrayIndexOutOfBoundsException, and IllegalArgumentException.
IOException:
• IOException is a subclass of Exception and represents exceptions related to input-output
operations.
• It typically indicates problems with reading from or writing to streams, files, or other input-
output sources.
• Examples of IOException subclasses include FileNotFoundException and EOFException.
SQLException:
• SQLException is a subclass of Exception and represents exceptions related to database
access and manipulation.
• It typically indicates problems with executing SQL statements, connecting to databases, or
accessing database resources.
FileNotFoundException:
• FileNotFoundException is a subclass of IOException and represents an exception that
occurs when attempting to access a file that does not exist.
• It typically indicates that the specified file path is invalid or that the file does not exist at
the specified location.
NullPointerException:
• NullPointerException is a subclass of RuntimeException and represents an exception that
occurs when attempting to access or invoke a method on a null object reference.
• It typically indicates a programming error where code expects an object to be non-null but
encounters null instead.
ArrayIndexOutOfBoundsException:
• ArrayIndexOutOfBoundsException is a subclass of RuntimeException and represents an
exception that occurs when attempting to access an array element with an invalid index
(i.e., outside the bounds of the array).
• It typically indicates a programming error where code accesses an array with an index that
is too large or too small.

5. Wrirte a Java program that includes a try block and a catch clause that processes the
ArithmeticException generated by the division-by-zero error
Ans: public class ArithmeticExceptionHandling {
public static void main(String[] args) {
int dividend = 10;
int divisor = 0;
try {
// Attempting to perform division operation that may throw ArithmeticException
int result = dividend / divisor;
System.out.println("Result of division: " + result);
} catch (ArithmeticException e) {
// Handling the ArithmeticException
System.out.println("An error occurred: " + e.getMessage());
System.out.println("Please ensure the divisor is not zero.");
}
// Code continues execution after exception handling
System.out.println("Program continues execution...");
}
}
In this program:
• We attempt to perform a division operation where divisor is zero, which will result in an
ArithmeticException.
• The division operation is enclosed within a try block.
• If an ArithmeticException occurs during the division operation, the exception is caught by
the catch clause.
• Within the catch block, we handle the exception by printing an error message to the
console.
• The program continues execution after the exception handling block, demonstrating that
the program does not terminate abruptly due to the exception.
When you run this program, you'll see the following output:
An error occurred: / by zero
Please ensure the divisor is not zero.
Program continues execution...

6. Create a try block that is likely to generate 3 types of exceptions and then incorporate
necessary try blocks to catch and handle them appropriately?
Ans: Below is a Java program that creates a try block likely to generate three types of exceptions:
ArithmeticException, ArrayIndexOutOfBoundsException, and NumberFormatException. The
program then incorporates necessary try blocks to catch and handle each exception appropriately:

public class MultipleExceptionsHandling {


public static void main(String[] args) {
try {
// Likely to generate ArithmeticException due to division by zero
int result = 10 / 0;

// Likely to generate ArrayIndexOutOfBoundsException due to accessing out-of-bounds


index
int[] numbers = {1, 2, 3};
int value = numbers[3];

// Likely to generate NumberFormatException due to parsing invalid integer


String str = "abc";
int intValue = Integer.parseInt(str);
} catch (ArithmeticException e) {
System.out.println("ArithmeticException caught: " + e.getMessage());
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("ArrayIndexOutOfBoundsException caught: " + e.getMessage());
} catch (NumberFormatException e) {
System.out.println("NumberFormatException caught: " + e.getMessage());
}

// Code continues execution after exception handling


System.out.println("Program continues execution...");
}
}
In this program:

• We have a try block that contains three statements, each likely to generate one of the
specified exceptions.
• We use separate catch blocks to catch and handle each type of exception.
• Within each catch block, we print an appropriate error message along with the exception
message using e.getMessage().
• After handling the exceptions, the program continues execution, and a message "Program
continues execution..." is printed to the console.

When you run this program, you'll see the appropriate error messages for each caught exception:

ArithmeticException caught: / by zero


ArrayIndexOutOfBoundsException caught: Index 3 out of bounds for length 3
NumberFormatException caught: For input string: "abc"
Program continues execution...

7. What are the types of exceptions in Java API. Explain with examples
Ans:
Checked Exceptions:
• Checked exceptions are the exceptions that are checked at compile-time by the
compiler.
• They are subclasses of Exception (but not RuntimeException).
• Checked exceptions represent anticipated error conditions that can occur during
program execution and must be either caught (handled) using a try-catch block or
declared in the method's throws clause.
• Examples of checked exceptions in the Java API include:
• IOException: Represents exceptions related to input-output operations, such as
reading from or writing to files, streams, or network connections.
• FileNotFoundException: Represents an exception that occurs when attempting to
access a file that does not exist.
• ParseException: Represents exceptions related to parsing operations, such as
parsing strings into dates or numbers.
import java.io.*;
public class CheckedExceptionExample {
public static void main(String[] args) {
try {
BufferedReader reader = new BufferedReader(new FileReader("example.txt"));
String line = reader.readLine();
System.out.println("Read line: " + line);
reader.close();
} catch (IOException e) {
System.out.println("An error occurred while reading the file: " + e.getMessage());
}
}
}
Unchecked Exceptions (Runtime Exceptions):

• Unchecked exceptions are the exceptions that are not checked at compile-time by
the compiler.
• They are subclasses of RuntimeException.
• Unchecked exceptions typically represent programming errors or unexpected
conditions that can occur during runtime and do not need to be caught or declared
explicitly in the throws clause.
• Examples of unchecked exceptions in the Java API include:
• NullPointerException: Represents an exception that occurs when attempting to
access or invoke a method on a null object reference.
• ArrayIndexOutOfBoundsException: Represents an exception that occurs when
attempting to access an array element with an invalid index.
• NumberFormatException: Represents an exception that occurs when attempting to
parse a string into a numeric format, but the string does not contain a valid numeric
representation.

public class UncheckedExceptionExample {


public static void main(String[] args) {
String str = null;
try {
int length = str.length();
System.out.println("Length of the string: " + length);
} catch (NullPointerException e) {
System.out.println("An error occurred: " + e.getMessage());
}
}
}
8. List out by an example the way to create a user defined exception?
Ans: // Custom exception class
class CustomException extends Exception {
public CustomException(String message) {
super(message);
}
}

// Example class that throws the custom exception


class Example {
public void performOperation(int value) throws CustomException {
if (value < 0) {
throw new CustomException("Value cannot be negative");
} else {
System.out.println("Operation performed successfully");
}
}
}

// Main class to demonstrate the usage of the custom exception


public class UserDefinedExceptionExample {
public static void main(String[] args) {
Example example = new Example();

try {
// Calling a method that may throw the custom exception
example.performOperation(-5);
} catch (CustomException e) {
// Handling the custom exception
System.out.println("Custom exception caught: " + e.getMessage());
}
}
}
• We define a custom exception class CustomException that extends the Exception class.
This class has a constructor that accepts a message to be displayed when the exception is
thrown.
• We have a class Example with a method performOperation() that may throw the custom
exception CustomException if the value passed to it is negative.
• In the main() method of the UserDefinedExceptionExample class, we create an instance of
Example and call the performOperation() method with a negative value.
• We handle the custom exception using a try-catch block and print the message associated
with the exception.

When you run this program, you'll see the following output:
Custom exception caught: Value cannot be negative
9. Explain the life cycle of the thread?
Ans: The life cycle of a thread in Java refers to the various states a thread can be in during its
lifetime. Threads in Java follow a well-defined life cycle, transitioning between different states as
they are created, started, executed, paused, and terminated. The life cycle of a thread can be
represented by a finite state machine with different states.

Draw the table in vertical direction of headdings in the table box


New:
The thread is in this state when it's created but not yet started.
The Thread object has been instantiated, but the start() method has not been invoked.
In this state, the thread has not yet been assigned system resources like CPU time.
Runnable:

• Once the start() method is called, the thread moves to the runnable state.
• In this state, the thread is ready to run, but it may not be running immediately because the
scheduler has not yet selected it to be the running thread.
• The thread scheduler selects threads in the runnable state to run based on thread priorities
and other scheduling algorithms.
Running:

• The thread moves from the runnable state to the running state when it's selected by the
thread scheduler to execute.
• In this state, the thread is actively executing its code.
• The run() method of the thread's Runnable object is being executed.
Blocked (Waiting):

• A thread moves to the blocked state when it's temporarily inactive or waiting for a resource.
• It may enter this state for reasons such as waiting for I/O operations to complete, waiting
for a lock, or waiting for a signal from another thread.
• The thread remains in the blocked state until the condition for which it was waiting is
satisfied.
Timed Waiting:

• Similar to the blocked state, a thread can also enter the timed waiting state when it's waiting
for a specific amount of time.
• This can occur when the thread calls methods such as Thread.sleep() or Object.wait() with
a timeout parameter.
Terminated (Dead):

• The thread moves to the terminated state when its run() method completes or when the
stop() method is called (though it's deprecated and should not be used).
• Once terminated, the thread cannot be restarted.
• After termination, the resources associated with the thread, such as memory and CPU
resources, are released.
10. What is a thread? Explain various stages of its life cycle.
Ans:

A thread is the smallest unit of execution within a process. In a multitasking operating system,
multiple threads can exist within a single process, allowing concurrent execution of multiple tasks.
Threads share the resources of the process to which they belong, including memory, file handles,
and other system resources.
New:

• The thread is in this state when it's created but not yet started.
• The Thread object has been instantiated, but the start() method has not been invoked.
• In this state, the thread has not yet been assigned system resources like CPU time.
Runnable:

• Once the start() method is called, the thread moves to the runnable state.
• In this state, the thread is ready to run, but it may not be running immediately because the
scheduler has not yet selected it to be the running thread.
• The thread scheduler selects threads in the runnable state to run based on thread priorities
and other scheduling algorithms.
Running:

• The thread moves from the runnable state to the running state when it's selected by the
thread scheduler to execute.
• In this state, the thread is actively executing its code.
• The run() method of the thread's Runnable object is being executed.
Blocked (Waiting):

• A thread moves to the blocked state when it's temporarily inactive or waiting for a resource.
• It may enter this state for reasons such as waiting for I/O operations to complete, waiting
for a lock, or waiting for a signal from another thread.
• The thread remains in the blocked state until the condition for which it was waiting is
satisfied.
Timed Waiting:

• Similar to the blocked state, a thread can also enter the timed waiting state when it's waiting
for a specific amount of time.
• This can occur when the thread calls methods such as Thread.sleep() or Object.wait() with
a timeout parameter.
Terminated (Dead):

• The thread moves to the terminated state when its run() method completes or when the
stop() method is called (though it's deprecated and should not be used).
• Once terminated, the thread cannot be restarted.
• After termination, the resources associated with the thread, such as memory and CPU
resources, are released.
11. Explain the process of creating threads using runnable Interface?
Ans: In Java, threads can be created by implementing the Runnable interface. This approach is
more flexible than extending the Thread class because a class can implement multiple interfaces,
but it can only extend one class.
Create a Runnable Implementation:
• Define a class that implements the Runnable interface.
• This class must provide an implementation for the run() method, which contains the code
that will be executed by the thread.
Instantiate the Runnable Object: Create an instance of the class implementing the Runnable
interface.
Create a Thread Object: Create an instance of the Thread class, passing the Runnable object as
a parameter to the constructor.
Start the Thread:
• Call the start() method on the Thread object to start the execution of the thread.
• The start() method internally calls the run() method of the Runnable object, executing the
code in a separate thread of execution.

// Step 1: Create a class that implements the Runnable interface


class MyRunnable implements Runnable {
@Override
public void run() {
// Code to be executed by the thread
for (int i = 0; i < 5; i++) {
System.out.println("Thread is running: " + i);
try {
Thread.sleep(1000); // Simulate some work by sleeping for 1 second
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class RunnableExample {
public static void main(String[] args) {
// Step 2: Instantiate the Runnable object
MyRunnable myRunnable = new MyRunnable();
// Step 3: Create a Thread object and pass the Runnable object to the constructor
Thread thread = new Thread(myRunnable);
thread.start(); // Step 4: Start the thread
// Main thread continues execution concurrently with the new thread
System.out.println("Main thread continues execution...");
}
}
Output: Main thread continues execution...
Thread is running: 0 Thread is running: 1 Thread is running: 2
Thread is running: 3 Thread is running: 4
12. Explain the process of creating threads using thread class with example?
Ans: Creating threads using the Thread class involves extending the Thread class and overriding
its run() method.
Create a Subclass of Thread:
• Define a class that extends the Thread class.
• Override the run() method in the subclass with the code that will be executed by the thread.
Instantiate the Thread Object: Create an instance of the subclass (the thread object).
Start the Thread:
• Call the start() method on the thread object to start the execution of the thread.
• The start() method internally calls the run() method, executing the code in a separate thread
of execution.
// Step 1: Create a subclass of Thread
class MyThread extends Thread {
@Override
public void run() {
// Code to be executed by the thread
for (int i = 0; i < 5; i++) {
System.out.println("Thread is running: " + i);
try {
Thread.sleep(1000); // Simulate some work by sleeping for 1 second
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class ThreadExample {
public static void main(String[] args) {
MyThread myThread = new MyThread(); // Step 2: Instantiate the Thread object
// Step 3: Start the thread
myThread.start();
// Main thread continues execution concurrently with the new thread
System.out.println("Main thread continues execution...");
}
}
In this example:
• We create a subclass MyThread of the Thread class and override its run() method with the
code to be executed by the thread.
• We instantiate the MyThread object.
• We call the start() method on the MyThread object to start the execution of the thread.
Output: Main thread continues execution...
Thread is running: 0
Thread is running: 1
Thread is running: 2
Thread is running: 3
Thread is running: 4
13. Explain thread synchronization with example?
Ans: Thread synchronization is the process of controlling the access of multiple threads to shared
resources to avoid data inconsistency or race conditions. In Java, synchronization is achieved using
the synchronized keyword, locks, and various synchronization mechanisms provided by the
java.util.concurrent package.

class Counter {
private int count = 0;
// Synchronized method to increment the count
public synchronized void increment() {
count++;
}
// Synchronized method to decrement the count
public synchronized void decrement() {
count--;
}
// Method to get the current count value
public synchronized int getCount() {
return count;
}
}
public class SynchronizationExample {
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
// Create and start multiple threads to increment and decrement the count
Thread incrementThread = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
Thread decrementThread = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.decrement();
}
});
incrementThread.start();
decrementThread.start();

// Wait for both threads to finish


incrementThread.join();
decrementThread.join();

// Print the final count value


System.out.println("Final count: " + counter.getCount());
}
}
14. Explain thread-thread communication with a example?
Ans: Thread communication refers to the mechanism by which threads coordinate their activities
and exchange data with each other. In Java, thread communication can be achieved using methods
such as wait(), notify(), and notifyAll() provided by the Object class.

class SharedResource {
private boolean flag = false; // Flag to indicate if a task is completed
// Method for thread 1 to perform a task
public synchronized void performTask1() throws InterruptedException {
// Wait until the flag is false (indicating task 2 is completed)
while (flag) {
wait();
}
System.out.println("Task 1 is performed"); // Perform task 1
flag = true; // Set flag to true
notify(); // Notify waiting thread
}
// Method for thread 2 to perform a task
public synchronized void performTask2() throws InterruptedException {
while (!flag) { // Wait until the flag is true (indicating task 1 is completed)
wait();
}
System.out.println("Task 2 is performed"); // Perform task 2
flag = false; // Set flag to false
notify(); // Notify waiting thread
}
}
public class ThreadCommunicationExample {
public static void main(String[] args) {
SharedResource sharedResource = new SharedResource();
Thread thread1 = new Thread(() -> { // Thread 1 performs task 1
try {
sharedResource.performTask1();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread thread2 = new Thread(() -> { // Thread 2 performs task 2
try {
sharedResource.performTask2();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread1.start();
thread2.start(); } }
15. Explain Daemon Threads with example?
Ans: In Java, daemon threads are a type of thread that runs in the background and provides services
to user threads. They are typically used for tasks that need to be performed periodically or
continuously in the background, such as garbage collection, monitoring, or background logging.

public class DaemonThreadExample {


public static void main(String[] args) {
// Create a daemon thread
Thread daemonThread = new Thread(() -> {
while (true) {
System.out.println("Daemon thread is running...");
try {
Thread.sleep(1000); // Sleep for 1 second
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});

// Set the daemon flag to true


daemonThread.setDaemon(true);

// Start the daemon thread


daemonThread.start();

// Main thread sleeps for some time


try {
Thread.sleep(3000); // Sleep for 3 seconds
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Main thread exiting...");
}
}

Key points about daemon threads:

• Daemon threads are automatically terminated when all user threads (non-daemon threads)
complete their execution or when the JVM exits.
• They do not prevent the JVM from exiting even if they are running.
• Daemon threads should be used for background tasks that are not critical to the
application's functionality.
• Examples of daemon threads in Java include garbage collection threads, finalizer threads,
and some internal system threads.
16. Explain Thread groups with example?
Ans:
In Java, ThreadGroup is a class that represents a group of threads. It provides a convenient way to
manage and manipulate multiple threads as a single entity. Threads can be organized into thread
groups for easier management and monitoring.

public class ThreadGroupExample {


public static void main(String[] args) {
// Create a thread group
ThreadGroup group = new ThreadGroup("MyThreadGroup");
// Create threads and add them to the thread group
Thread thread1 = new Thread(group, () -> {
while (true) {
System.out.println("Thread 1 is running...");
try {
Thread.sleep(1000); // Sleep for 1 second
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread thread2 = new Thread(group, () -> {
while (true) {
System.out.println("Thread 2 is running...");
try {
Thread.sleep(1000); // Sleep for 1 second
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread1.start(); // Start the threads
thread2.start();
// Print information about the thread group
group.list();
}
}
Key points about ThreadGroup:
• Threads can be added to a thread group either explicitly by passing the group to the Thread
constructor or implicitly by creating threads from a parent thread that belongs to the group.
• Threads within the same group share certain properties and behavior, such as the group's
uncaught exception handler.
• The ThreadGroup class provides methods for managing threads in the group, such as
enumerating threads, interrupting threads, and setting the maximum priority for threads in
the group.
• Thread groups can be nested, allowing hierarchical organization of threads.

You might also like