java unit2
java unit2
Java allows the creation of multi-threaded programs where multiple threads can execute
simultaneously. Threads are the smallest unit of a process. In Java, we can create threads in two
ways:
Both methods require overriding the run() method, which defines the code that will be executed by
the thread.
Thread Methods:
Method Purpose
start() Starts the execution of the thread by calling the run() method internally.
sleep(long
Pauses the thread execution for the specified number of milliseconds.
millis)
Causes the current thread to wait until the thread it’s called on has completed
join()
execution.
java
CopyEdit
Thread t;
String name;
public ThDemo(String n) {
name = n;
try {
} catch (InterruptedException e) {
System.out.println(e);
class Test {
try {
t2.t.join();
t3.t.join();
} catch (InterruptedException e) {
System.out.println(e);
1. isAlive() Method:
o Before calling join(), the isAlive() method checks if a thread is still in the running
state.
2. join() Method:
o This method ensures that the main thread waits for each thread (like t1, t2, t3 in the
example) to complete execution before it proceeds.
o The main thread will pause at the join() method call until the thread it is called on
finishes.
o Once each thread completes, the main thread resumes and checks again using
isAlive().
o At this point, isAlive() returns false for each thread, indicating they are no longer
alive.
• join(): Ensures that the main thread waits for a thread to finish before proceeding.
These methods are essential in managing multithreading and ensuring that threads run efficiently
and in a controlled order.
This written explanation should help you understand how the isAlive() and join() methods work in
Java, allowing you to effectively use them in your multi-threaded programs.
Synchronization in Threads
In Java, synchronization is used to prevent the race condition when multiple threads try to access a
shared resource. When multiple threads attempt to access the same resource concurrently, data
corruption or inconsistent results can occur. Synchronization ensures that only one thread can access
the shared resource at a time.
• synchronized keyword: This keyword is used to make a method or block of code thread-safe
by allowing only one thread to execute it at any given time.
• When multiple threads try to access a synchronized method on the same object, only one
thread is allowed to enter the method at a time, while others are blocked until the current
thread finishes.
The example code you provided demonstrates the usage of synchronization using the synchronized
keyword.
Code:
java
CopyEdit
class CallMe {
System.out.print("[" + name);
try {
} catch (InterruptedException e) {}
System.out.println("]");
// Constructor
}
class Test {
// Start three threads that will try to access the same method
Explanation:
o The mainFun(String name) method is synchronized, which means only one thread
can execute it at any given time. If another thread tries to call this method while it's
already being executed by one thread, it will be blocked until the current thread
finishes.
o When the Middle class is instantiated, it starts a new thread that calls the mainFun
method.
o Starts three threads (t1, t2, and t3) that all try to call the synchronized mainFun
method.
• The three threads (t1, t2, and t3) will try to call the synchronized mainFun method on the
same object obj.
• Since the method is synchronized, only one thread will be able to execute it at any given
time.
• The first thread will print its message, then pause for 1 second (simulated by
Thread.sleep(1000)), and finally print a closing bracket. The second thread will have to wait
for the first to finish before it can start its execution.
csharp
CopyEdit
[Dhananjay]
[Kumar]
[Sharma]
• Maintaining Thread Safety: Synchronization helps achieve thread safety by ensuring that
only one thread can execute a method or block of code at a time, reducing the risk of issues
like race conditions.
• Deadlock: If two threads are each waiting for the other to release a lock, neither will
proceed, causing a deadlock. This is a common problem when working with synchronization.
• Performance: Synchronization can slow down the performance because it involves locking
and unlocking, which reduces the number of threads that can access the synchronized
method at the same time.
In Java, Input and Output (I/O) refers to the process of reading data from an input source (such as a
file, keyboard, or network socket) and writing data to an output destination (such as a file, console,
or network socket). Java provides a comprehensive set of APIs to handle I/O operations, commonly
known as the Java I/O API.
3. The java.io package contains all classes for performing I/O operations.
4. File Handling is one of the core features provided by Java I/O API.
5. Streams represent the flow of data that can be read from or written to.
Streams are used for I/O operations because they make reading and writing data efficient by
representing a continuous flow of data. A stream can be attached to a source (input) or destination
(output) and allows the system to perform I/O operations without needing to manage data in bulk.
Java IO Streams
In Java, a stream is a sequence of data. It’s called a "stream" because, like a stream of water, the data
flows continuously from one source to a destination. Streams have no concept of indexing the data,
and data flows in a linear fashion, one byte or character at a time.
Types of Streams
1. InputStream:
o Purpose: An InputStream is used to read data from a source such as a file, array,
peripheral device, or socket.
o Base Class: java.io.InputStream is the base class for all input streams in Java.
Methods of InputStream:
o read(): Reads the next byte of data from the input stream.
o close(): Closes the stream and releases any system resources associated with it.
o read(byte[] arg): Reads bytes into an array from the input stream.
o skip(long arg): Skips over the specified number of bytes of data from the input
stream.
Example:
java
CopyEdit
int data;
in.close();
2. OutputStream:
o Base Class: java.io.OutputStream is the base class for all output streams in Java.
Methods of OutputStream:
o flush(): Flushes the output stream, ensuring that all buffered data is written out.
o close(): Closes the output stream and releases any system resources associated with
it.
Example:
java
CopyEdit
out.write(data.getBytes());
out.close();
Java I/O streams are broadly categorized into Byte Streams and Character Streams:
1. Byte Streams:
• Purpose: They handle I/O of raw binary data (e.g., image files, audio files, etc.).
• Classes:
o InputStream
o OutputStream
Example:
java
CopyEdit
int byteData;
System.out.print(byteData);
fileInput.close();
2. Character Streams:
• Purpose: They handle I/O of character data and are used for reading and writing text files.
• Classes:
o Reader
o Writer
• These streams handle data as 16-bit characters (UTF-16 encoding), making them ideal for
handling text.
Example:
java
CopyEdit
int character;
System.out.print((char) character);
fileReader.close();
The Java I/O API makes it easy to perform file operations like reading from and writing to files. Java
provides Byte Streams and Character Streams for working with files:
java
CopyEdit
import java.io.*;
int data;
System.out.print((char) data);
file.close();
Conclusion
• Java I/O is essential for working with files, reading data, and producing output based on user
input.
• The Java I/O package provides InputStream and OutputStream classes for handling byte-
level data, and Reader and Writer classes for handling character-level data.
• Java I/O is used to interact with various I/O devices and files through a variety of APIs,
stream classes, and methods provided by the java.io package.
4o mini
1. Checked Exceptions
2. Unchecked Exceptions
1. Checked Exceptions
Checked exceptions are exceptions that are explicitly checked during the compile-time. These
exceptions are typically caused by conditions outside the program's control, such as file handling,
network issues, database errors, etc. The compiler forces the programmer to handle or declare these
exceptions.
How to handle Checked Exceptions: You are required to handle checked exceptions using try-catch
blocks or by declaring the exception with the throws keyword.
Example:
java
CopyEdit
import java.io.*;
class CheckedExceptionExample {
try {
} catch (IOException e) {
2. Unchecked Exceptions
Unchecked exceptions are exceptions that occur during the runtime of the program. These
exceptions are typically caused by programming errors, such as logic errors or improper use of data.
Unchecked exceptions are subclasses of the RuntimeException class and do not need to be declared
or handled explicitly.
How to handle Unchecked Exceptions: Although these exceptions can be handled using try-catch
blocks, they are typically not required to be handled explicitly by the programmer. They can be
caught to prevent application crashes, but they do not need to be declared using throws.
Example:
java
CopyEdit
try {
} catch (ArithmeticException e) {
There are also a few other categories of exceptions based on their occurrence and behavior:
3. Errors
Errors are exceptions that typically represent serious problems that a program cannot recover from.
These are not exceptions in the typical sense, and they are not meant to be caught or handled by the
program.
• Examples of Errors:
o OutOfMemoryError – Occurs when the Java Virtual Machine (JVM) runs out of
memory.
o StackOverflowError – Occurs when the stack of a thread overflows (typically due to
deep recursion).
Note: Errors are usually not handled as they indicate critical problems in the system.
• Throwable
▪ Checked Exceptions
Custom Exceptions
In Java, you can also define your own exception classes by extending the Exception or
RuntimeException class.
java
CopyEdit
super(message);
} else {
System.out.println("Valid age");
try {
} catch (InvalidAgeException e) {
System.out.println(e.getMessage());
Conclusion
• Custom Exceptions: You can define your own exceptions for specific scenarios.
The Java Virtual Machine (JVM) is responsible for the handling of exceptions during runtime. When
an exception is thrown, the JVM reacts by performing a series of steps:
1. Detecting an Exception
When an exception occurs during program execution, the JVM detects it and looks for the nearest
appropriate exception handler (i.e., a catch block or a method declared with throws).
• If a try-catch block exists in the current method, the JVM executes the corresponding catch
block.
2. Stack Unwinding
As the exception propagates up the call stack, the JVM begins a process called stack unwinding.
During this process:
• The JVM will check each method in the call stack to find a matching catch block.
• If the method has opened resources (such as files or database connections), the JVM may
execute the finally block to close those resources.
• Once a matching catch block is found, the exception is handled, and the program can
continue execution.
3. Termination of Program
If no exception handler is found by the JVM (after unwinding the stack), the JVM will terminate the
program.
• Example:
java
CopyEdit
• The exception is uncaught, and the JVM will print the stack trace to the console, then
terminate the program.
4. Fatal Errors
In Java, exception handling is a mechanism to handle runtime errors, maintaining the normal flow of
the application. The keywords try, catch, finally, throw, and throws are used in various ways to handle
exceptions in Java. Below is an explanation of each of these keywords and how they work together.
1. try Block
The try block is used to wrap code that may potentially throw an exception. If an exception occurs
within the try block, the JVM immediately transfers control to the corresponding catch block, if one
exists.
• Syntax:
java
CopyEdit
try {
• Example:
java
CopyEdit
try {
} catch (ArithmeticException e) {
2. catch Block
The catch block is used to catch and handle exceptions thrown by the try block. You can specify the
type of exception you want to handle. If an exception of that type occurs, the program flow will jump
to the catch block and execute the code there.
• Syntax:
java
CopyEdit
catch (ExceptionType e) {
// handle exception
• Example:
java
CopyEdit
try {
int result = 10 / 0;
} catch (ArithmeticException e) {
3. finally Block
The finally block is used to execute code that must run regardless of whether an exception occurs or
not. This is often used for cleanup operations, such as closing files, releasing resources, or closing
database connections. Even if an exception is thrown and not caught, the finally block will still
execute.
• Syntax:
java
CopyEdit
finally {
• Example:
java
CopyEdit
try {
} finally {
• Control Flow:
o If an exception occurs and is caught, the finally block executes after the catch block.
o If no exception occurs, the finally block executes after the try block.
4. throw Keyword
The throw keyword is used to manually throw an exception in a method or block of code. You can
throw exceptions of any type, including custom exceptions.
• Syntax:
java
CopyEdit
• Example:
java
CopyEdit
• Use: This is used when you want to explicitly trigger an exception in your code. For example,
if certain conditions are not met, you may throw an exception to signal an error.
5. throws Keyword
The throws keyword is used in a method declaration to indicate that the method might throw certain
exceptions. It is used to pass the responsibility of handling the exception to the calling method. If a
method declares an exception using throws, the caller is required to handle that exception using a
try-catch block or by declaring it with throws.
• Syntax:
java
CopyEdit
// method code
• Example:
java
CopyEdit
methodThatThrowsException();
} catch (Exception e) {
• Use:
o It is used when a method might throw an exception but doesn’t want to handle it
within the method itself.
o The calling method must either handle the exception or declare it using throws.
java
CopyEdit
try {
int result = 10 / 0;
} catch (ArithmeticException e) {
} finally {
}
}
• Explanation:
o The finally block is executed no matter what, ensuring that the necessary cleanup or
logging is performed.
java
CopyEdit
try {
methodThatThrowsException();
} catch (IOException e) {
System.out.println("Throwing an exception...");
• Explanation:
o The method signature uses throws to declare that it may throw an IOException,
passing the responsibility of handling it to the calling method.
o The calling method (main()) catches the IOException using a try-catch block.
Key Differences
• throws: Declares that a method may throw an exception and passes the responsibility of
handling it to the calling method.
Thread in Java:
A thread is a lightweight process, and it is the smallest unit of execution in a program. Java allows for
multithreaded programming, where multiple threads can run concurrently, sharing the same
memory space. Threads can be created in Java using the Thread class or implementing the Runnable
interface.
Threads are commonly used to perform multiple tasks simultaneously, like reading data from a file,
executing background tasks, or responding to user inputs in a graphical user interface (GUI).
A thread in Java goes through several states during its life cycle. These states represent different
stages of a thread's execution and are controlled by the Java Virtual Machine (JVM). The thread life
cycle consists of the following states:
o When a thread object is created, it is in the "new" state. In this state, the thread is
not yet started. The thread is only instantiated but not yet eligible for execution.
o Example:
java
CopyEdit
2. Runnable:
o After the start() method is invoked on the thread, it enters the runnable state. A
thread in the runnable state is ready to run but is waiting for the CPU to schedule it.
This means it is either actively executing or waiting for the CPU to allocate time for it.
o Example:
java
CopyEdit
3. Blocked:
o A thread enters the blocked state when it is waiting for a resource or monitor lock to
be released. For example, if a thread tries to access a synchronized block or method
that another thread has locked, it will be blocked.
o Example:
▪ Thread A may try to access a synchronized method but has to wait until
thread B releases the lock on that method.
4. Waiting:
o A thread enters the waiting state when it is waiting indefinitely for another thread to
perform a specific action. The thread is not using the CPU, and it can only move to
the runnable state when notified by another thread using methods like notify() or
notifyAll().
o Example:
java
CopyEdit
synchronized (obj) {
5. Timed Waiting:
o A thread enters the timed waiting state when it is waiting for a specified period. The
thread will automatically return to the runnable state after the specified waiting time
has elapsed.
o Methods that cause a thread to enter this state include sleep(long milliseconds),
join(long milliseconds), wait(long milliseconds), and Thread.sleep().
o Example:
java
CopyEdit
6. Terminated (Dead):
o A thread enters the terminated state when its run() method completes execution, or
if it is terminated due to an exception or interruption. Once a thread has finished
execution, it cannot be restarted.
o Example:
▪ After completing the execution of its run() method, the thread moves to the
terminated state and can no longer be started again.
Thread Life Cycle Flow:
A thread moves through these states based on the method calls made on the thread (like start(),
sleep(), join(), wait(), etc.).
Here are some key methods used to transition between the various states of a thread:
1. start():
2. sleep(long millis):
o Causes the thread to sleep for a specified period, entering the timed waiting state.
3. join(long millis):
o Causes the current thread to wait until the thread it is called on has finished
executing, moving that thread to waiting.
4. wait():
5. notify() / notifyAll():
o These methods are used to notify one or all waiting threads that they can move back
to the runnable state.
6. interrupt():
7. isAlive():
o This method returns true if the thread is alive (i.e., it has been started and has not
yet finished), and false otherwise.
java
CopyEdit
try {
System.out.println(Thread.currentThread().getName() + " is running");
} catch (InterruptedException e) {
try {
t1.join(); // Main thread waits for t1 to finish (t1 goes to 'waiting' state)
} catch (InterruptedException e) {
e.printStackTrace();
Thread priority is a way of determining the order in which threads are executed. Threads are given a
priority value between Thread.MIN_PRIORITY (1) and Thread.MAX_PRIORITY (10), with a default
value of Thread.NORM_PRIORITY (5). A higher priority thread is likely to get CPU time before lower
priority threads.
However, the actual scheduling of threads depends on the thread scheduler of the JVM and the
operating system. Therefore, thread priority is not guaranteed to ensure that high-priority threads
will always execute before low-priority threads.
Setting Thread Priority:
o You can set the priority of a thread using the setPriority() method.
o Thread.MIN_PRIORITY = 1
o Thread.NORM_PRIORITY = 5 (default)
o Thread.MAX_PRIORITY = 10
java
CopyEdit
t3.start();
Inter-thread communication is a mechanism that allows threads to communicate with each other
and synchronize their execution. Java provides a set of methods in the Object class, which all classes
inherit, to facilitate communication between threads. These methods are:
• wait()
• notify()
• notifyAll()
These methods allow threads to wait for certain conditions to be met, and notify other threads
when the condition changes, enabling synchronization between threads.
• wait() causes the current thread to release the lock it holds and enter the waiting state. The
thread will remain in the waiting state until it is notified by another thread.
• The thread can be notified via notify() or notifyAll() from another thread.
• The wait() method must be called from within a synchronized block or synchronized
method.
Syntax:
java
CopyEdit
• notify() wakes up a single thread that is waiting on the object's monitor (lock). If multiple
threads are waiting, only one of them will be notified.
• It is important to note that calling notify() does not immediately allow the waiting thread to
proceed; it simply makes it eligible to be scheduled for execution when the lock is available.
Syntax:
java
CopyEdit
• notifyAll() wakes up all the threads that are waiting on the object's monitor (lock). This
method is useful when you want to notify multiple threads waiting on the same condition.
Syntax:
java
CopyEdit
How It Works:
• Synchronized Block: To use wait(), notify(), or notifyAll(), you need to use synchronization.
This ensures that only one thread has access to the shared resource at any given time.
• Condition Variables: These are used to manage inter-thread communication. Threads can
wait for certain conditions to be met before proceeding.