Java Unit - 3
Java Unit - 3
At its core, I/O in Java revolves around the idea of streams. A stream is a sequence of data that flows from
a source to a destination. Java provides two main types of streams:
1. Byte Streams: These streams handle data in the form of individual bytes (8-bit units). They are
suitable for all types of data, including binary files (like images, audio, video) and text files (where
each character is treated as one or more bytes depending on the encoding).
2. Character Streams: These streams handle data in the form of characters. They are specifically
designed for text-based data and automatically handle character encoding and decoding. This
makes them more convenient and efficient for working with text.
❖ Input and Output (I/O) are fundamental concepts used for reading data from input sources (like the
keyboard or files) and writing data to output destinations (like the screen or files). Java provides several
classes and methods to handle I/O operations, which are part of the java.io, java.util, and
java.nio packages.
What is try-with-resources?
It's a special try block that automatically closes resources (like file streams) when the block ends.
It works with all classes that implement the AutoCloseable interface (which FileInputStream and
FileOutputStream do).
In Java, when using byte streams like FileInputStream and FileOutputStream, you can automatically close
the file using a try-with-resources block. This ensures that your file is closed properly, even if an exception
occurs.
Character streams are used for text data (not binary). They read and write 16-bit Unicode characters,
making them ideal for:
Main Classes
Task Class Description
Read FileReader Reads character by character
Write FileWriter Writes characters to a file
❖ Java I/O Classes
Java provides a rich set of classes for performing I/O operations. Some of the key classes include:
1. InputStream and OutputStream: These abstract classes form the foundation for byte-oriented I/O
operations. They provide methods for reading and writing bytes from/to various sources and
destinations.
2. Reader and Writer: These abstract classes are used for character-based I/O operations. They provide
methods for reading and writing characters from/to character-based streams.
3. FileInputStream and FileOutputStream: These classes allow reading from and writing to files in a byte-
oriented manner.
4. FileReader and FileWriter: These classes enable reading from and writing to files using character-
oriented operations.
5. BufferedInputStream and BufferedOutputStream: These classes provide buffering capabilities, which
can significantly improve I/O performance by reducing the number of system calls.
6. BufferedReader and BufferedWriter: These classes offer buffered reading and writing of character data,
enhancing I/O efficiency when working with character-based streams.
What is Multithreading?
Multithreading is a programming feature that allows multiple threads (smaller units of a process) to run
concurrently. It helps improve performance and resource utilization.
Benefits of Multithreading
• Improved Responsiveness: In GUI applications, for example, long-running tasks can be executed in
separate threads, preventing the user interface from freezing.
• Increased Performance: On multi-core systems, multithreading can allow true parallel execution of
tasks, leading to faster overall execution times for computationally intensive applications.
• Better Resource Utilization: Threads within the same process share resources, which can be more
efficient than running multiple separate processes.
• Simplified Complex Tasks: Breaking down a complex task into smaller, concurrent sub-tasks can
sometimes lead to a more manageable and understandable program structure.
Challenges of Multithreading
• Complexity: Multithreaded programs can be more complex to design, implement, and debug due
to issues like race conditions, deadlocks, and thread interference.
• Synchronization Issues: When multiple threads access shared resources, you need to carefully
manage their access to prevent data corruption and unexpected behavior. This often involves using
synchronization mechanisms.
• Overhead: Creating and managing threads has some overhead in terms of CPU time and memory.
Creating too many threads can sometimes degrade performance due to excessive context
switching.
• Platform Dependence: Thread behavior and scheduling can vary slightly across different operating
systems and JVM implementations.
Thread Class :-
The Thread class in Java belongs to the java.lang package. When we create an instance of the Thread class
(or its subclass) and call its start() method, a new thread is spawned, and the run() method of that
Thread object is executed in the new thread.
Runnable Interface :-
The Runnable interface is a functional interface in Java used to define a task that can be run by a thread. It
is part of the java.lang package and contains only one method. Any class that implements the Runnable
interface can have its run() method executed by a thread
Life Cycle of a Thread in Java
A thread in Java goes through several states during its lifetime. These states are defined in the
Thread.State enum and represent the life cycle of a thread from creation to termination.
1. NEW: When you create a Thread object (either by extending Thread or implementing Runnable), it's in
the NEW state. The thread will remain in this state until you call its start() method.
2. RUNNABLE: Once you call start(), the thread transitions to the RUNNABLE state.This doesn't mean it's
actively running right now. It means the thread is eligible to be run by the JVM.
3. BLOCKED: A thread enters the BLOCKED state when it tries to acquire a lock on an object that is
currently held by another thread. This happens when the thread attempts to enter a synchronized
block or method.
4. WAITING: A thread enters the WAITING state when it calls methods like Object.wait(), Thread.join()
(without a timeout).
5. TIMED_WAITING: This state is similar to WAITING, but the thread will only wait for a specified amount
of time. Methods that cause a thread to enter TIMED_WAITING include Thread.sleep(long millis),
Object.wait(long timeout).
6. TERMINATED: A thread reaches the TERMINATED state when its run() method has finished executing.
Once a thread is in the TERMINATED state, it cannot be restarted. If you want to execute the same task
again, you need to create a new Thread object.
What is Synchronization in Java?
Synchronization is a mechanism in Java that ensures only one thread can access a shared resource at a
time. It is used to prevent race conditions when multiple threads try to read/write shared data
simultaneously.
Why Synchronization?
When multiple threads access shared variables or methods without synchronization, they can interfere
with each other and lead to incorrect or inconsistent results.
What is a synchronized Method?
A synchronized method is a method where only one thread can execute it at a time per object instance.
When a thread calls a synchronized method It locks the object (this) & Other threads must wait until the
lock is released.
What is a synchronized Statement?
A synchronized block allows you to lock only a specific section of code, rather than the whole method.
This provides better performance and more control than synchronizing an entire method.