Multithreading and file input-output — Unit 4 Notes (Java Programming)

BCS504 · Unit 4

Multithreading and file input-output notes — Unit 4

Free unit-wise study notes on multithreading and file input-output for Java Programming, Semester 5 of B.Tech — Computer Science & Engineering — key concepts, examples, important questions and a revision checklist for semester exams.

Multithreading and file input-output

Notebook — 20 pages

Page 1

Wink Notes

B.Tech CSE — 5th Semester

Java Programming

Unit - 4

1. Introduction to Multithreading

Multithreading is a Java feature that allows concurrent execution of two or more parts of a program for maximum utilization of CPU. Each part is called a thread.

1.1 Process vs Thread

  • Process: A heavy-weight, independent program in execution (like MS Word). It has its own memory space.
  • Thread: A light-weight sub-process. Multiple threads exist within the same process and share the same memory space, making context-switching between threads much faster than between processes.

Next — Creating Threads

1 of 20

Page 2

Wink Notes

B.Tech CSE — 5th Semester

Java Programming

Unit - 4

2. Creating Threads in Java

There are two ways to create a thread in Java.

2.1 Extending the Thread Class

class MyThread extends Thread {
    public void run() { // The code to be executed
        System.out.println("Thread is running");
    }
}

// Usage
MyThread t1 = new MyThread();
t1.start(); // NEVER call run() directly!

Calling `run()` executes the code on the main thread, defeating the purpose. Calling `start()` creates a new call stack and hands it to the OS to execute concurrently.

Next — The Runnable Interface

2 of 20

Page 3

Wink Notes

B.Tech CSE — 5th Semester

Java Programming

Unit - 4

3. The Runnable Interface

Because Java does not support multiple inheritance, if your class already extends another class, it cannot extend `Thread`. The preferred approach is implementing `Runnable`.

3.1 Syntax

class MyTask implements Runnable {
    public void run() {
        System.out.println("Task running");
    }
}

// Usage
Thread t2 = new Thread(new MyTask());
t2.start();

This approach separates the Task (Runnable) from the Worker (Thread), adhering to better Object-Oriented design.

Next — Thread Life Cycle

3 of 20

Page 4

Wink Notes

B.Tech CSE — 5th Semester

Java Programming

Unit - 4

4. The Thread Life Cycle

A thread goes through various states managed by the JVM Thread Scheduler.

  • New: Thread object created, but `start()` not called.
  • Runnable: `start()` called. Waiting for the OS scheduler to assign it CPU time.
  • Running: Actively executing the `run()` method.
  • Blocked/Waiting: Paused (e.g., waiting for File I/O, waiting for a lock, or sleeping via `Thread.sleep()`).
  • Terminated: The `run()` method has completed.

You cannot restart a Terminated thread. Calling `start()` again throws an `IllegalThreadStateException`.

Next — Thread Priorities and Join

4 of 20

Page 5

Wink Notes

B.Tech CSE — 5th Semester

Java Programming

Unit - 4

5. Thread Priorities and Join

5.1 Thread Priorities

Every thread has a priority from 1 (MIN_PRIORITY) to 10 (MAX_PRIORITY). Default is 5. The Thread Scheduler usually favors higher priorities, but it is highly OS-dependent and never guaranteed.

5.2 The `join()` Method

If Thread A calls `t2.join()`, Thread A halts execution until Thread `t2` finishes and dies. It is used to force synchronization of dependent tasks.

Thread t1 = new Thread(task);
t1.start();
t1.join(); // Main thread pauses here until t1 is completely done.
System.out.println("t1 finished, main resuming.");

Next — Synchronization Problem

5 of 20

Page 6

Wink Notes

B.Tech CSE — 5th Semester

Java Programming

Unit - 4

6. The Synchronization Problem (Race Conditions)

Because threads share memory, if two threads try to modify the exact same variable at the exact same millisecond, data corruption occurs. This is a Race Condition.

6.1 The Bank Account Example

If Alice and Bob both withdraw 50fromasharedaccountwith50 from a shared account with 100 simultaneously:

  • Alice's thread reads balance ($100).
  • Bob's thread reads balance ($100).
  • Alice's thread deducts 50 and writes $50.
  • Bob's thread deducts 50 and writes $50.

The account now has 50insteadof50 instead of 0. The database is corrupted.

Next — The 'synchronized' Keyword

6 of 20

Page 7

Wink Notes

B.Tech CSE — 5th Semester

Java Programming

Unit - 4

7. The 'synchronized' Keyword

To solve race conditions, Java uses Locks (Monitors). Every object in Java has a hidden intrinsic lock.

7.1 Synchronized Methods

By adding `synchronized` to a method, you force threads to acquire the object's lock before executing it. Only one thread can hold the lock at a time.

// Only one thread can execute this at a time for a given object
public synchronized void withdraw(int amt) {
    balance = balance - amt;
}

7.2 Synchronized Blocks

Synchronizing entire methods is slow. You can synchronize just the critical lines of code using a block.

Next — Deadlock

7 of 20

Page 8

Wink Notes

B.Tech CSE — 5th Semester

Java Programming

Unit - 4

8. Deadlock

Synchronization prevents data corruption, but introduces a new problem: Deadlock.

8.1 The Deadlock Scenario

  • Thread 1 locks Object A, and needs Object B to proceed.
  • Thread 2 locks Object B, and needs Object A to proceed.
  • Both threads wait forever for the other to release the lock. The application completely freezes.

8.2 Prevention

Avoid nested locks. Always acquire locks in the exact same order across all threads. Use timeouts (`tryLock()`) available in the modern `java.util.concurrent` package.

Next — Inter-thread Communication

8 of 20

Page 9

Wink Notes

B.Tech CSE — 5th Semester

Java Programming

Unit - 4

9. Inter-thread Communication (wait/notify)

Sometimes threads need to coordinate. E.g., a Consumer thread must wait for a Producer thread to create data before consuming it.

9.1 Object Methods

These methods belong to the `Object` class, not the `Thread` class, and MUST be called inside a `synchronized` context.

  • `wait()`: Tells the current thread to release the lock and go to sleep until someone notifies it.
  • `notify()`: Wakes up a single random thread that is waiting on this object's lock.
  • `notifyAll()`: Wakes up all threads waiting on this object's lock.

Next — File I/O Basics

9 of 20

Page 10

Wink Notes

B.Tech CSE — 5th Semester

Java Programming

Unit - 4

10. File Input/Output (I/O) Basics

The `java.io` package provides classes for system input and output through data streams, serialization and the file system.

10.1 Concept of a Stream

A stream is a logical sequence of data moving from a Source (Input) to a Destination (Output). It abstracts away the physical devices (keyboard, network, hard drive).

10.2 Two Types of Streams

  • Byte Streams: Used for handling raw binary data like images, audio, or compiled classes. (e.g., `InputStream`, `OutputStream`). Processes data 8-bits at a time.
  • Character Streams: Used for handling human-readable text data. (e.g., `Reader`, `Writer`). Processes data 16-bits at a time (Unicode), resolving encoding issues automatically.

Next — Byte Streams

10 of 20

Page 11

Wink Notes

B.Tech CSE — 5th Semester

Java Programming

Unit - 4

11. Byte Streams (FileInputStream / FileOutputStream)

Used primarily for reading and writing binary files like images.

11.1 File Copy Example

try (FileInputStream in = new FileInputStream("image.jpg");
     FileOutputStream out = new FileOutputStream("copy.jpg")) {
     
    int c;
    // read() returns the byte as an integer (0-255), or -1 if EOF
    while ((c = in.read()) != -1) {
        out.write(c);
    }
}

Reading files byte-by-byte is extremely slow because it hits the hard drive thousands of times. It is almost always wrapped in a Buffered stream in production.

Next — Character Streams

11 of 20

Page 12

Wink Notes

B.Tech CSE — 5th Semester

Java Programming

Unit - 4

12. Character Streams (FileReader / FileWriter)

Used for reading and writing text files (`.txt`, `.csv`, `.java`).

12.1 Buffered Character Streams

Instead of hitting the hard drive for every single character, `BufferedReader` reads a massive chunk of the file into RAM (the buffer), and feeds it to your program line-by-line incredibly fast.

try (BufferedReader br = new BufferedReader(new FileReader("data.txt"))) {
    String line;
    while ((line = br.readLine()) != null) {
        System.out.println(line);
    }
}

Next — The File Class

12 of 20

Page 13

Wink Notes

B.Tech CSE — 5th Semester

Java Programming

Unit - 4

13. The File Class

The `java.io.File` class does not actually read or write data. It represents the path to a file or directory, and is used for metadata operations.

13.1 Common Operations

File f = new File("C:/temp/notes.txt");

if (f.exists()) {
    System.out.println("Size: " + f.length() + " bytes");
    System.out.println("Is Directory? " + f.isDirectory());
    f.delete();
} else {
    // Creates an empty file
    f.createNewFile(); 
}

Note: In modern Java (NIO.2), the `java.nio.file.Path` and `Files` classes are preferred over `java.io.File` for these operations.

Next — Serialization

13 of 20

Page 14

Wink Notes

B.Tech CSE — 5th Semester

Java Programming

Unit - 4

14. Object Serialization

Serialization is the process of converting the state of a live Java object in RAM into a byte stream. This byte stream can be saved to a hard drive or sent over a network. Deserialization is the reverse process.

14.1 The Serializable Interface

To serialize an object, its class must implement the `java.io.Serializable` interface. This is a Marker Interface (it has no methods). It simply flags to the JVM that the object is allowed to be converted to bytes.

14.2 The `transient` Keyword

If you have sensitive data in an object (like a password field) that you do NOT want saved to the hard drive during serialization, you mark the variable as `transient`. The JVM will skip it.

Next — ObjectInputStream

14 of 20

Page 15

Wink Notes

B.Tech CSE — 5th Semester

Java Programming

Unit - 4

15. Implementing Serialization

15.1 Writing an Object

Student s1 = new Student("Alice", 25);
try (ObjectOutputStream oos = new ObjectOutputStream(
        new FileOutputStream("student.ser"))) {
    
    oos.writeObject(s1); // Converts to bytes and saves
}

15.2 Reading an Object

try (ObjectInputStream ois = new ObjectInputStream(
        new FileInputStream("student.ser"))) {
    
    // Must cast the returned Object back to Student
    Student s2 = (Student) ois.readObject(); 
}

Next — Scanner Class

15 of 20

Page 16

Wink Notes

B.Tech CSE — 5th Semester

Java Programming

Unit - 4

16. The Scanner Class

The `java.util.Scanner` class is used to parse primitive types and strings using regular expressions. It is most commonly used for reading user input from the console.

16.1 Reading from System.in

Scanner sc = new Scanner(System.in);

System.out.print("Enter age: ");
int age = sc.nextInt(); // Parses the integer

System.out.print("Enter name: ");
String name = sc.next(); // Reads a single word

Gotcha: If you call `sc.nextLine()` immediately after `nextInt()`, it will instantly read the leftover newline character in the buffer and skip user input. Always clear the buffer with an empty `sc.nextLine()` after reading primitives.

Next — Executors Framework

16 of 20

Page 17

Wink Notes

B.Tech CSE — 5th Semester

Java Programming

Unit - 4

17. Modern Multithreading: Executors

Creating a new `Thread()` object every time a user connects to a server consumes massive RAM and OS resources. The modern approach (Java 5+) uses Thread Pools via the Executor Framework.

17.1 Thread Pools

A Thread Pool creates a fixed number of threads (e.g., 10) at startup. You submit 100 Runnables to the pool. The 10 threads process tasks, and when finished, they don't die; they recycle and pick up the next task.

// Creates a pool of 5 reusable threads
ExecutorService pool = Executors.newFixedThreadPool(5);

for (int i = 0; i < 100; i++) {
    pool.execute(new MyTask()); // Submit task to the pool
}
pool.shutdown(); // Stop accepting new tasks

Next — Callable and Future

17 of 20

Page 18

Wink Notes

B.Tech CSE — 5th Semester

Java Programming

Unit - 4

18. Callable and Future

The `Runnable` interface has a flaw: its `run()` method is `void`. It cannot return a result or throw a checked exception.

18.1 The Callable Interface

`Callable<T>` represents a task that returns a result of type `T`.

18.2 The Future Object

When you submit a Callable to a Thread Pool, it immediately hands you back a `Future` object. This is a placeholder for the result that will arrive later.

Future<Integer> result = pool.submit(new CallableTask());
// ... do other work on main thread ...
// .get() blocks until the thread finishes and returns the integer
int finalValue = result.get();

Next — Concurrent Collections

18 of 20

Page 19

Wink Notes

B.Tech CSE — 5th Semester

Java Programming

Unit - 4

19. Concurrent Collections

Standard collections (`ArrayList`, `HashMap`) are not thread-safe. Wrapping them entirely in `synchronized` blocks is extremely slow.

19.1 java.util.concurrent

This package provides highly optimized thread-safe collections that avoid locking the entire object.

  • `ConcurrentHashMap`: Locks only the specific segment/bucket being written to, allowing multiple threads to read and write to different parts of the Map simultaneously.
  • `CopyOnWriteArrayList`: Every time you add/remove an element, it creates a completely fresh copy of the underlying array. Highly efficient when reads vastly outnumber writes.

Next — Java NIO Intro

19 of 20

Page 20

Wink Notes

B.Tech CSE — 5th Semester

Java Programming

Unit - 4

20. Java NIO (New I/O)

Standard `java.io` is strictly Blocking. If a thread calls `read()` on a network socket, the thread freezes until data arrives. A web server with 10,000 idle connections would need 10,000 blocked threads, crashing the server.

20.1 Non-Blocking I/O (NIO)

Java NIO introduces Channels, Buffers, and Selectors.

  • Selectors: Allow a single thread to monitor thousands of connections. The thread asks the Selector 'Which sockets have data ready to read right now?', processes them instantly, and loops back. This is how highly scalable servers (like Node.js or Netty) operate.

20 of 20

Continue in this subject