☕ JAVA PROGRAMMING
I/O • Generics • Multithreading • JDBC
Modules Covered
Unit I → I/O Fundamentals – Streams, File I/O, Serialization
Unit II → Generics – Custom Classes, Diamond Operator, Bounded Types & Wildcards
Unit III → Multithreading – Lifecycle, Thread/Runnable, Priority, Sync, ITC
Unit IV → JDBC – Drivers, CRUD Operations, Non-conventional DBs
Detailed Notes • 16-Day Study Plan • Viva Q&A (Easy→Hard) • Coding Problems
📅 16-Day Study Plan
1.5–2 hrs/day. Always run the code you write — I/O and threads especially need hands-on practice.
Day Topic Tasks Revise
Day Byte & Character FileInputStream/OutputStream, —
1 Streams FileReader/Writer — copy a file both ways
Day Buffered Streams BufferedReader readLine(), Day 1
2 BufferedWriter, compare speed
Day Data & Object DataInputStream/OutputStream; write Day 2
3 Streams primitives to file
Day Serialization Serialize/deserialize 3 objects; test Day 3
4 transient; SerialVersionUID
Day Generics – Classes Write generic Pair<T,U>, Stack<T>; Day 4
5 & Methods generic swap method
Day Bounded Types & extends/super bounds; wildcard ? Day 5
6 Wildcards programs; covariance
Day Thread Basics Create 5 threads via Thread class AND Day 6
7 Runnable; observe interleaving
Day Thread Lifecycle & Set priorities; trace Day 7
8 Priority NEW→RUNNABLE→BLOCKED→TERMI
NATED
Day Synchronization Race condition demo; fix with Day 8
9 synchronized method & block
Day Inter-thread Producer-Consumer using wait()/notify(); Day 9
10 Communication observe without sync
Day Revision – Units I-III Answer all viva Qs for Units 1-3 aloud; re- Days 1-10
11 do 1 coding Q each
Day JDBC Setup + Install MySQL/SQLite; load driver; get Day 11
12 Connection Connection; ping DB
Day JDBC – CREATE & CREATE TABLE; prepared statement Day 12
13 INSERT INSERT; batch insert 10 rows
Day JDBC – SELECT & executeQuery(); ResultSet iteration; Day 13
14 UPDATE UPDATE with WHERE
Day JDBC – DELETE & DELETE; commit/rollback; transaction Day 14
15 Transactions demo with exception
Day Full Mock + JDBC SQLite/MongoDB JDBC; answer all viva All
16 Non-conv Qs; 2 coding Qs/unit
📘 Unit I: I/O Fundamentals
1.1 I/O Overview
Java I/O is based on streams — a sequence of data. All I/O is in [Link] and [Link] packages.
Category Classes Data Type Direction
Byte Streams FileInputStream / Raw bytes (images, Read / Write
FileOutputStream audio)
Character Streams FileReader / FileWriter Characters (text files, Read / Write
Unicode)
Buffered Streams BufferedReader / BufferedWriter Buffered for Read / Write
performance
Data Streams DataInputStream / Java primitives (int, Read / Write
DataOutputStream double…)
Object Streams ObjectInputStream / Serialized Java objects Read / Write
ObjectOutputStream
Print Streams PrintWriter / PrintStream Formatted text output Write only
Stream direction: InputStream/Reader = reading INTO Java. OutputStream/Writer = writing
OUT of Java.
1.2 Byte Streams — FileInputStream / FileOutputStream
Lowest-level streams. Work with raw bytes (0-255). Suitable for binary files (images, PDFs). Reads one
byte at a time — inefficient without buffering.
import [Link].*;
// Write bytes to file
try (FileOutputStream fos = new FileOutputStream("[Link]")) {
byte[] data = {72, 101, 108, 108, 111}; // H e l l o
[Link](data);
[Link]("Written successfully");
}
// Read bytes from file
try (FileInputStream fis = new FileInputStream("[Link]")) {
int byteRead;
while ((byteRead = [Link]()) != -1) { // -1 = end of stream
[Link]((char) byteRead);
}
}
// Copy a file using byte streams
try (FileInputStream fis = new FileInputStream("[Link]");
FileOutputStream fos = new FileOutputStream("[Link]")) {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = [Link](buffer)) != -1) {
[Link](buffer, 0, bytesRead);
}
}
1.3 Character Streams — FileReader / FileWriter
Work with characters (16-bit Unicode). Best for text files. Automatically handle character encoding.
import [Link].*;
// Write text to file
try (FileWriter fw = new FileWriter("[Link]")) {
[Link]("Hello, Java I/O!\n");
[Link]("Second line here.");
}
// Read text from file (char by char)
try (FileReader fr = new FileReader("[Link]")) {
int ch;
while ((ch = [Link]()) != -1) {
[Link]((char) ch);
}
}
1.4 Buffered Streams — BufferedReader / BufferedWriter
Wrap around other streams, adding an in-memory buffer. Drastically reduces I/O operations (one buffer
read vs thousands of single-byte reads).
import [Link].*;
// BufferedWriter — write lines
try (BufferedWriter bw = new BufferedWriter(new FileWriter("[Link]"))) {
[Link]("Alice,90"); [Link]();
[Link]("Bob,75"); [Link]();
[Link]("Charlie,85"); [Link]();
}
// BufferedReader — read lines
try (BufferedReader br = new BufferedReader(new FileReader("[Link]"))) {
String line;
while ((line = [Link]()) != null) { // readLine() = killer feature
[Link](line);
}
}
[Link]() is the most commonly used method for reading text files line-by-
line. Returns null at end of file (NOT -1).
1.5 DataInputStream / DataOutputStream
Read and write Java primitive types in a portable binary format. Data must be read back in the EXACT
same order it was written.
import [Link].*;
// Write primitives
try (DataOutputStream dos = new DataOutputStream(
new FileOutputStream("[Link]"))) {
[Link](42);
[Link](3.14159);
[Link](true);
[Link]("Hello Java"); // writes UTF-8 string
}
// Read back in SAME ORDER
try (DataInputStream dis = new DataInputStream(
new FileInputStream("[Link]"))) {
[Link]([Link]()); // 42
[Link]([Link]()); // 3.14159
[Link]([Link]()); // true
[Link]([Link]()); // Hello Java
}
1.6 Serialization & Deserialization
Serialization = converting a Java object into a byte stream (to save to file / send over network).
Deserialization = reconstructing the object from the byte stream.
Rule: The class MUST implement [Link] (marker interface — no methods to
implement).
import [Link].*;
// Step 1: Make class Serializable
class Student implements Serializable {
private static final long serialVersionUID = 1L; // version control
String name;
int rollNo;
double cgpa;
transient String password; // NOT serialized — sensitive data
Student(String n, int r, double c, String p) {
name=n; rollNo=r; cgpa=c; password=p;
}
public String toString() {
return name+" | "+rollNo+" | "+cgpa+" | pwd:"+password;
}
}
// Step 2: Serialize (write object)
Student s = new Student("Shivam", 101, 9.2, "secret123");
try (ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("[Link]"))) {
[Link](s);
[Link]("Serialized: " + s);
}
// Step 3: Deserialize (read object)
try (ObjectInputStream ois = new ObjectInputStream(
new FileInputStream("[Link]"))) {
Student loaded = (Student) [Link]();
[Link]("Deserialized: " + loaded);
// password will be null — transient not saved
}
Keyword/Concept Purpose
Serializable Marker interface — marks class as serializable
serialVersionUID Version ID for compatibility — must match on deserialization
transient Excludes a field from serialization (e.g., passwords, temp data)
ObjectOutputStream Writes serialized objects to a stream
ObjectInputStream Reads and reconstructs objects from a stream
If serialVersionUID doesn't match between serialized and current class,
InvalidClassException is thrown. Always declare it explicitly.
1.7 Stream Class Hierarchy
Abstract Base Purpose Key Concrete Classes
InputStream Byte reading base FileInputStream, BufferedInputStream,
DataInputStream, ObjectInputStream
OutputStream Byte writing base FileOutputStream, BufferedOutputStream,
DataOutputStream, ObjectOutputStream
Reader Char reading base FileReader, BufferedReader, InputStreamReader,
StringReader
Writer Char writing base FileWriter, BufferedWriter, OutputStreamWriter,
PrintWriter
1.8 Viva Questions – Unit I
[Easy] What is a stream in Java I/O?
Ans: A sequence of data (bytes or characters) flowing from a source to a destination. Java uses streams
as an abstraction for all I/O.
[Easy] What is the difference between byte streams and character streams?
Ans: Byte streams (InputStream/OutputStream) handle raw bytes — suitable for binary data. Character
streams (Reader/Writer) handle 16-bit Unicode characters — suitable for text.
[Easy] What is the advantage of BufferedReader over FileReader?
Ans: BufferedReader uses an internal buffer, reducing disk access frequency. readLine() reads full lines.
Significantly faster for text file reading.
[Easy] What is serialization?
Ans: Converting a Java object's state into a byte stream for storage or transmission. Deserialization
reconstructs the object from that byte stream.
[Medium] What is the transient keyword?
Ans: Marks a field to be excluded from serialization. Useful for sensitive data (passwords) or data that can
be recomputed.
[Medium] What is serialVersionUID and why is it important?
Ans: A unique ID for each Serializable class. Used to verify class versions during deserialization. If they
don't match, InvalidClassException is thrown.
[Medium] What is the difference between DataOutputStream and ObjectOutputStream?
Ans: DataOutputStream writes primitive types (int, double, etc.) in binary. ObjectOutputStream writes
entire Java objects using serialization.
[Hard] What happens to static fields during serialization?
Ans: Static fields are NOT serialized — they belong to the class, not the object. They retain their current
JVM values during deserialization.
[Hard] What is try-with-resources and why is it important for I/O?
Ans: Automatically closes streams after the try block, even if an exception occurs. Prevents resource
leaks — critical since I/O streams hold OS file handles.
1.9 Coding Questions – Unit I
Q1. Write a program to copy a text file line-by-line using BufferedReader and BufferedWriter.
Hint: try-with-resources; while((line=[Link]())!=null) [Link](line+newLine)
Q2. Serialize a list of 3 Product objects to a file and deserialize them back. Verify all fields are
restored.
Hint: List<Product> implements Serializable; writeObject/readObject the list
Q3. Write and read a student record (name, age, marks, fee) to a binary file using
DataOutputStream/DataInputStream.
Hint: Write in exact order; read back same order
Q4. Use transient on password field in User class. Serialize and deserialize. Show password is null
after deserialization.
Hint: Verify [Link] == null after reading back
Q5. Count the number of lines, words, and characters in a text file using BufferedReader.
Hint: readLine for lines; split(" ") for words; [Link]() for chars
📗 Unit II: Generics
2.1 Why Generics?
Generics provide compile-time type safety — catch type errors at compile time, not runtime. Eliminate
ClassCastException and remove the need for explicit casting.
// Without Generics — unsafe, verbose
List list = new ArrayList();
[Link]("Java"); [Link](42); // mixed types — no error!
String s = (String) [Link](1); // ClassCastException at runtime
// With Generics — safe, clean
List<String> list = new ArrayList<>();
[Link]("Java");
// [Link](42); // COMPILE ERROR — caught early
String s = [Link](0); // no cast needed
2.2 Generic Class
// Single type parameter
class Box<T> {
private T value;
Box(T v) { [Link] = v; }
T get() { return value; }
void set(T v) { [Link] = v; }
@Override
public String toString() { return "Box[" + value + "]"; }
}
Box<String> strBox = new Box<>("Hello");
Box<Integer> intBox = new Box<>(42);
Box<Double> dblBox = new Box<>(3.14);
[Link]([Link]()); // Hello
[Link]([Link]()); // 42
// Two type parameters
class Pair<K, V> {
K key; V value;
Pair(K k, V v) { key=k; value=v; }
@Override
public String toString() { return key + " -> " + value; }
}
Pair<String, Integer> entry = new Pair<>("Score", 95);
[Link](entry); // Score -> 95
2.3 Type Inference — Diamond Operator <>
Java 7 introduced the diamond operator <> to avoid repeating type parameters. Compiler infers the
type from the left side.
// Before Java 7 — verbose
Map<String, List<Integer>> map = new HashMap<String, List<Integer>>();
// Java 7+ with diamond — cleaner, compiler infers right side
Map<String, List<Integer>> map = new HashMap<>();
List<String> names = new ArrayList<>();
Pair<String, Integer> p = new Pair<>("Age", 25);
Diamond operator <> tells the compiler: infer the generic types from the left-hand
declaration. Cannot be used with anonymous classes.
2.4 Generic Methods
// Generic method — type parameter before return type
public static <T> void swap(T[] arr, int i, int j) {
T temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
Integer[] nums = {1, 2, 3, 4, 5};
swap(nums, 0, 4); // works for any type
// Generic method returning result
public static <T extends Comparable<T>> T findMax(T[] arr) {
T max = arr[0];
for (T item : arr)
if ([Link](max) > 0) max = item;
return max;
}
[Link](findMax(new Integer[]{3,1,4,1,5,9})); // 9
[Link](findMax(new String[]{"cherry","apple"})); // cherry
2.5 Bounded Type Parameters
Restrict what types T can be — T must be a specific type or its subtype (upper bound) or supertype
(lower bound).
Upper Bound: extends
// T must be Number or its subclass (Integer, Double, Float…)
public static <T extends Number> double sum(List<T> list) {
double total = 0;
for (T item : list) total += [Link]();
return total;
}
[Link](sum([Link](1, 2, 3))); // 6.0 (Integer)
[Link](sum([Link](1.5, 2.5))); // 4.0 (Double)
// sum([Link]("a","b")); // COMPILE ERROR — String not a Number
// Multiple bounds
class DataHolder<T extends Comparable<T> & Serializable> {
T data;
// T must implement both Comparable AND Serializable
}
Lower Bound: super (with Wildcards)
// ? super Integer means: Integer OR any supertype of Integer
// (Integer, Number, Object)
public static void addNumbers(List<? super Integer> list) {
[Link](10); [Link](20); [Link](30);
}
List<Number> numbers = new ArrayList<>();
addNumbers(numbers); // valid — Number is supertype of Integer
2.6 Wildcards
Wildcards (?) represent an unknown type. Used in method parameters for flexibility.
Wildcard Syntax Meaning Use Case
Unbounded <?> Any type Read-only, print
any list
Upper Bounded <? extends T> T or subtype of T Read from
structure
(covariant)
Lower Bounded <? super T> T or supertype of T Write to structure
(contravariant)
// Unbounded wildcard — read from any List
public static void printList(List<?> list) {
for (Object o : list) [Link](o + " ");
}
printList([Link](1,2,3)); // integers
printList([Link]("a","b","c")); // strings
// Upper bounded — sum Numbers
public static double sumList(List<? extends Number> list) {
return [Link]().mapToDouble(Number::doubleValue).sum();
}
sumList([Link](1, 2, 3)); // Integer list — OK
sumList([Link](1.0, 2.5)); // Double list — OK
// Lower bounded — add Integers to list
public static void addIntegers(List<? super Integer> list) {
for (int i=1; i<=5; i++) [Link](i);
}
PECS: Producer Extends, Consumer Super. If list produces values (you read), use extends.
If list consumes values (you write), use super.
2.7 Type Erasure
At runtime, generic type information is erased — replaced with Object or the bounded type. Generics
are a compile-time feature only.
// At compile time: List<String> and List<Integer>
// At runtime: both become List (raw type)
List<String> ls = new ArrayList<>();
List<Integer> li = new ArrayList<>();
[Link]([Link]() == [Link]()); // true — both ArrayList
2.8 Viva Questions – Unit II
[Easy] What are generics in Java?
Ans: A compile-time feature that allows classes, interfaces, and methods to operate on typed parameters,
providing type safety without casting.
[Easy] What is the diamond operator?
Ans: <> in Java 7+. Lets the compiler infer the generic type from the left-hand declaration, reducing
boilerplate. e.g., new ArrayList<>()
[Medium] What is an upper-bounded wildcard?
Ans: <? extends T> — accepts T or any subtype of T. Used to read from a generic structure (covariant
position).
[Hard] What is the PECS principle?
Ans: Producer Extends, Consumer Super. Use <? extends T> when reading from a structure (it produces
values). Use <? super T> when writing to it (it consumes values).
[Medium] What is type erasure?
Ans: The JVM removes generic type info at runtime — replaced with Object or bounds. Generics are
purely a compile-time safety feature.
[Hard] Can we create an array of generic type like new T[10]?
Ans: No. Due to type erasure, T is not known at runtime, so the JVM cannot create a typed array. Use
ArrayList<T> instead.
[Hard] What is the difference between <T extends Number> and <? extends Number>?
Ans: <T extends Number> is a type parameter used in class/method declaration — T can be used
elsewhere. <? extends Number> is a wildcard for method parameters — the type is unknown.
2.9 Coding Questions – Unit II
Q1. Create a generic Stack<T> class with push, pop, peek, isEmpty, size methods. Test with Integer
and String.
Hint: Internal ArrayList<T>; push=add to end; pop=remove last
Q2. Write a generic method <T extends Comparable<T>> to sort an array using bubble sort.
Hint: Compare with compareTo(); works for Integer, String, Double
Q3. Write a generic Pair<K,V> class. Create a list of Pairs and sort by key using Comparator lambda.
Hint: List<Pair<String,Integer>>; sort by [Link]
Q4. Write a method using upper-bounded wildcard to calculate the sum of any List of Numbers.
Hint: <? extends Number>; [Link]()
Q5. Demonstrate PECS: write a copy method that reads from List<? extends T> and writes to List<?
super T>.
Hint: static <T> void copy(List<? extends T> src, List<? super T> dest)
📙 Unit III: Multithreading
3.1 What is a Thread?
A thread is the smallest unit of a process that can execute independently. Multithreading allows multiple
threads to run concurrently, improving CPU utilization and application responsiveness.
Term Definition
Process An independent program in execution with its own memory space
Thread A lightweight sub-process; shares memory of its parent process
Multithreading Multiple threads executing concurrently in one process
Concurrency Tasks making progress by switching rapidly (single CPU)
Parallelism Tasks truly executing simultaneously (multi-core CPU)
3.2 Thread Lifecycle
NEW → RUNNABLE → RUNNING → BLOCKED/WAITING/TIMED_WAITING →
TERMINATED
State Description How to Enter How to Exit
NEW Thread created but not new Thread() call start()
started
RUNNABLE Ready to run; waiting for start() called CPU allocated
CPU → RUNNING
RUNNING Executing on CPU CPU allocated yield(), sleep(),
wait(), done
BLOCKED Waiting for lock Trying to get lock Lock released
(synchronized) another holds
WAITING Indefinitely waiting for wait(), join() (no notify() /
notification timeout) notifyAll()
TIMED_WAITING Waiting for a specified time sleep(ms), wait(ms), Timeout elapsed
join(ms)
TERMINATED Thread has finished run() completes or Cannot restart
execution exception
3.3 Creating Threads — Method 1: Thread Class
class MyThread extends Thread {
String taskName;
MyThread(String name) { taskName = name; }
@Override
public void run() { // define what the thread does
for (int i = 1; i <= 3; i++) {
[Link](taskName + ": step " + i
+ " [Thread: " + getName() + "]");
try { [Link](100); } catch (InterruptedException e) {}
}
}
}
MyThread t1 = new MyThread("Download");
MyThread t2 = new MyThread("Upload");
[Link](); // starts new thread — calls run() in new thread
[Link](); // starts concurrently — ORDER IS NOT GUARANTEED
// [Link](); // WRONG — calls run() in current thread (no new thread!)
3.4 Creating Threads — Method 2: Runnable Interface
class MyTask implements Runnable {
String name;
MyTask(String n) { name = n; }
@Override
public void run() {
for (int i = 1; i <= 3; i++) {
[Link](name + i + [Link]().getName());
}
}
}
Runnable task1 = new MyTask("Parser");
Thread t1 = new Thread(task1, "ParserThread");
Thread t2 = new Thread(new MyTask("Loader"), "LoaderThread");
[Link]();
[Link]();
// Lambda shorthand (Runnable is @FunctionalInterface)
Thread t3 = new Thread(() -> {
[Link]("Lambda thread: " + [Link]().getName());
});
[Link]();
Aspect extends Thread implements Runnable
Inheritance Uses up the single inheritance Free to extend another class
slot
Code reuse Thread code tightly coupled Task separated from Thread — better
OOP
Preferred? Simple cases Almost always preferred
Lambda? No Yes — Runnable is functional interface
Resource sharing Cannot share same Runnable Multiple threads can share one Runnable
3.5 Important Thread Methods
Method Description Usage
start() Creates new thread, calls run() [Link]() — always use this, not run()
run() Thread's task — do not call Override in Thread subclass
directly
Method Description Usage
sleep(ms) Pauses current thread for ms [Link](500) — static method
milliseconds
join() Wait for another thread to finish [Link]() — waits until t1 terminates
join(ms) Wait for at most ms milliseconds [Link](1000)
yield() Hint to scheduler to pause [Link]() — not guaranteed
current thread
isAlive() Check if thread is still running [Link]()
interrupt() Interrupt a sleeping/waiting [Link]()
thread
getName() Get thread's name [Link]().getName()
setName() Set thread's name [Link]("MyThread")
currentThread() Get reference to current thread [Link]()
3.6 Thread Priorities
Thread priority hints the scheduler which thread to prefer. Range: 1 (MIN) to 10 (MAX), default 5
(NORM). NOT guaranteed — OS-dependent.
class PriorityDemo extends Thread {
PriorityDemo(String name, int priority) {
setName(name);
setPriority(priority);
}
public void run() {
[Link](getName() + " priority:" + getPriority() + " running");
}
}
Thread low = new PriorityDemo("Low", Thread.MIN_PRIORITY); // 1
Thread normal = new PriorityDemo("Normal", Thread.NORM_PRIORITY); // 5
Thread high = new PriorityDemo("High", Thread.MAX_PRIORITY); // 10
[Link](); [Link](); [Link]();
// High priority likely runs first — but ORDER IS NOT GUARANTEED
3.7 Synchronization
When multiple threads access shared data simultaneously, Race Conditions occur — data becomes
inconsistent. Synchronization ensures only ONE thread accesses critical code at a time.
Race Condition (Problem)
class Counter {
int count = 0;
void increment() { count++; } // count++ is NOT atomic!
}
Counter c = new Counter();
Thread t1 = new Thread(() -> { for(int i=0;i<1000;i++) [Link](); });
Thread t2 = new Thread(() -> { for(int i=0;i<1000;i++) [Link](); });
[Link](); [Link](); [Link](); [Link]();
[Link]([Link]); // LIKELY < 2000 due to race condition!
Fix 1: synchronized Method
class Counter {
int count = 0;
synchronized void increment() { // only one thread at a time
count++;
}
}
// Now count will always be 2000
Fix 2: synchronized Block (finer granularity)
class Counter {
int count = 0;
Object lock = new Object();
void increment() {
// only critical section is synchronized
synchronized(lock) {
count++;
}
// other non-critical code can run concurrently
}
}
Every Java object has an intrinsic lock (monitor). synchronized method locks 'this'.
synchronized(obj) locks a specific object. Only one thread can hold a lock at a time.
Type What is Locked Use When
synchronized method Entire method; locks 'this' Simple — small synchronized section
synchronized block Only the block; custom lock Better performance; avoid locking
object 'this'
static synchronized Class-level lock (Class object) Protecting static shared data
3.8 Inter-Thread Communication (ITC)
Threads can communicate using wait(), notify(), and notifyAll() — defined in Object class. Used to
coordinate between threads (e.g., Producer-Consumer).
Method Description Releases Lock?
wait() Current thread releases lock and waits Yes
until notified
wait(ms) Waits until notified or timeout expires Yes
notify() Wakes up one randomly chosen waiting No — lock released when
thread synchronized exits
notifyAll() Wakes up ALL waiting threads No
wait() and notify() MUST be called from inside a synchronized block/method — otherwise
IllegalMonitorStateException.
Producer-Consumer Pattern
class SharedBuffer {
private int data;
private boolean hasData = false;
synchronized void produce(int value) throws InterruptedException {
while (hasData) wait(); // wait if buffer full
data = value;
hasData = true;
[Link]("Produced: " + value);
notify(); // wake up consumer
}
synchronized int consume() throws InterruptedException {
while (!hasData) wait(); // wait if buffer empty
hasData = false;
[Link]("Consumed: " + data);
notify(); // wake up producer
return data;
}
}
SharedBuffer buf = new SharedBuffer();
Thread producer = new Thread(() -> {
try { for(int i=1;i<=5;i++) [Link](i); }
catch (InterruptedException e) { [Link](); }
});
Thread consumer = new Thread(() -> {
try { for(int i=1;i<=5;i++) [Link](); }
catch (InterruptedException e) { [Link](); }
});
[Link](); [Link]();
3.9 Deadlock
Deadlock occurs when two or more threads are waiting for each other's locks — forming a circular wait.
All involved threads are permanently blocked.
// Thread 1 holds lockA, waits for lockB
// Thread 2 holds lockB, waits for lockA → DEADLOCK!
Object lockA = new Object(), lockB = new Object();
Thread t1 = new Thread(() -> {
synchronized(lockA) {
try { [Link](50); } catch (InterruptedException e) {}
synchronized(lockB) { [Link]("T1 done"); }
}
});
Thread t2 = new Thread(() -> {
synchronized(lockB) {
try { [Link](50); } catch (InterruptedException e) {}
synchronized(lockA) { [Link]("T2 done"); }
}
});
[Link](); [Link](); // → DEADLOCK — neither prints
Prevention: always acquire multiple locks in the SAME ORDER across all threads. Use
tryLock() with timeout from [Link].
3.10 Viva Questions – Unit III
[Easy] What is a thread?
Ans: The smallest unit of process execution. Threads share the process's memory space and run
concurrently for better performance.
[Easy] What are the two ways to create a thread?
Ans: 1) Extend Thread class and override run(). 2) Implement Runnable interface and pass to Thread
constructor. Runnable is preferred.
[Easy] What is the difference between start() and run()?
Ans: start() creates a new thread and calls run() in it. run() called directly executes in the CURRENT
thread — no new thread is created.
[Medium] What are the thread states?
Ans: NEW, RUNNABLE, RUNNING, BLOCKED, WAITING, TIMED_WAITING, TERMINATED.
[Medium] What is a race condition?
Ans: When two threads access and modify shared data concurrently, producing unpredictable results.
Solved using synchronization.
[Medium] What is synchronized keyword?
Ans: A Java keyword that ensures only one thread at a time can execute a method/block by acquiring the
object's intrinsic lock.
[Hard] What is the difference between wait() and sleep()?
Ans: wait(): releases the lock and waits for notify(); must be in synchronized block. sleep(): pauses thread
but does NOT release the lock; static method of Thread.
[Hard] What is deadlock and how do you prevent it?
Ans: When two threads wait for each other's locks indefinitely. Prevention: always acquire locks in the
same order; use timeout-based locking; minimize synchronization scope.
[Hard] Why must wait() and notify() be called in a synchronized block?
Ans: Because they operate on the object's monitor (intrinsic lock). Without holding the lock, the JVM
throws IllegalMonitorStateException.
[Hard] What is the difference between notify() and notifyAll()?
Ans: notify() wakes one randomly selected waiting thread. notifyAll() wakes all waiting threads — safer but
less efficient. Prefer notifyAll() to avoid missed notifications.
3.11 Coding Questions – Unit III
Q1. Create 3 threads printing 'Thread-1 running', 'Thread-2 running', 'Thread-3 running'. Use both
Thread class and Runnable.
Hint: Show both approaches; observe interleaved output
Q2. Simulate a race condition: 2 threads increment a shared counter 10000 times each. Show
incorrect result without sync, correct with sync.
Hint: Without synchronized: count < 20000; with: count == 20000
Q3. Implement Producer-Consumer with wait()/notify() using a shared buffer of capacity 1.
Hint: SharedBuffer with produce() and consume(); both synchronized
Q4. Create 3 threads with priorities 1, 5, 10. Show that higher priority tends to run more.
Hint: setPriority(Thread.MAX_PRIORITY); run a counting loop
Q5. Use [Link]() to ensure threads complete in a specific order: T1 first, then T2, then T3.
Hint: [Link](); [Link](); [Link](); [Link](); [Link]()
Q6. Demonstrate deadlock with two threads and two locks. Then fix it by changing lock acquisition
order.
Hint: Show deadlock first; fix by always locking in same order
📒 Unit IV: Java Database Programming (JDBC)
4.1 What is JDBC?
Java Database Connectivity (JDBC) is a Java API that provides a standard interface for connecting
Java applications to relational databases. It is part of the Java SE platform ([Link] package).
Component Role
DriverManager Manages database drivers; creates connections
Connection Represents a session with the database
Statement Executes static SQL queries
PreparedStatement Executes parameterized SQL (precompiled, safe from SQL injection)
CallableStatement Calls stored procedures
ResultSet Holds query results; cursor-based row iteration
SQLException Handles database errors
4.2 JDBC Drivers
Type Name Description Example
Type 1 JDBC-ODBC Bridge Uses ODBC driver; deprecated in Sun JDBC-ODBC
Java 8+
Type 2 Native-API Uses DB vendor's native C libraries Oracle OCI
Type 3 Network Protocol Middleware server translates to DB DataDirect
protocol
Type 4 Thin Driver (Pure Direct Java-to-DB socket connection; MySQL Connector/J
Java) BEST
Always use Type 4 (Thin/Pure Java) drivers for modern applications — no native libraries
needed, fully portable.
4.3 JDBC Connection Steps (The 5-Step Process)
Step Code Description
1. [Link]("[Link] Register the JDBC driver (auto in JDBC 4+)
Load [Link]")
Driver
2. Get [Link](url Open connection to database
Conn , user, pwd)
ection
3. [Link]() or Create SQL executor
Creat [Link](sql)
e
State
ment
4. [Link]() or Run the SQL
Step Code Description
Execu [Link]()
te
SQL
5. [Link](); [Link](); Free DB resources
Close [Link]()
Reso
urces
4.4 Full JDBC Setup — MySQL
import [Link].*;
// JDBC URL format: jdbc:mysql://host:port/databaseName
String url = "jdbc:mysql://localhost:3306/school";
String user = "root";
String pass = "your_password";
// Establish connection (try-with-resources auto-closes)
try (Connection conn = [Link](url, user, pass)) {
[Link]("Connected: " + [Link]().getDatabaseProductName());
} catch (SQLException e) {
[Link]("Connection failed: " + [Link]());
}
4.5 CREATE Table
String createSQL = """
CREATE TABLE IF NOT EXISTS students (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
marks DOUBLE,
grade CHAR(2),
enrolled DATE
)""";
try (Connection conn = [Link](url, user, pass);
Statement stmt = [Link]()) {
[Link](createSQL);
[Link]("Table created!");
}
4.6 INSERT — PreparedStatement (Safe!)
String insertSQL = "INSERT INTO students(name, marks, grade) VALUES(?, ?, ?)";
try (Connection conn = [Link](url, user, pass);
PreparedStatement ps = [Link](insertSQL)) {
// Insert first record
[Link](1, "Alice");
[Link](2, 92.5);
[Link](3, "A");
[Link]();
// Insert second record (reuse PreparedStatement)
[Link](1, "Bob");
[Link](2, 76.0);
[Link](3, "B");
[Link]();
[Link]("Records inserted!");
}
Always use PreparedStatement for INSERT/UPDATE with user data — prevents SQL
Injection. Never concatenate user input into SQL strings!
4.7 SELECT — ResultSet
String selectSQL = "SELECT * FROM students WHERE marks > ?";
try (Connection conn = [Link](url, user, pass);
PreparedStatement ps = [Link](selectSQL)) {
[Link](1, 80.0);
ResultSet rs = [Link]();
[Link]("%-5s %-15s %-8s %s%n","ID","Name","Marks","Grade");
[Link]("-".repeat(40));
while ([Link]()) { // move cursor to next row
int id = [Link]("id");
String name = [Link]("name");
double marks = [Link]("marks");
String grade = [Link]("grade");
[Link]("%-5d %-15s %-8.1f %s%n", id, name, marks, grade);
}
}
4.8 UPDATE
String updateSQL = "UPDATE students SET grade = ? WHERE marks >= ?";
try (Connection conn = [Link](url, user, pass);
PreparedStatement ps = [Link](updateSQL)) {
[Link](1, "A+");
[Link](2, 90.0);
int rowsAffected = [Link]();
[Link]("Updated " + rowsAffected + " row(s)");
}
4.9 DELETE
String deleteSQL = "DELETE FROM students WHERE id = ?";
try (Connection conn = [Link](url, user, pass);
PreparedStatement ps = [Link](deleteSQL)) {
[Link](1, 3);
int deleted = [Link]();
[Link]("Deleted " + deleted + " row(s)");
}
4.10 Transactions
By default, JDBC auto-commits each statement. For atomic operations (all or nothing), disable auto-
commit and manually commit or rollback.
try (Connection conn = [Link](url, user, pass)) {
[Link](false); // BEGIN TRANSACTION
try (PreparedStatement ps1 = [Link](
"UPDATE accounts SET balance = balance - ? WHERE id = ?");
PreparedStatement ps2 = [Link](
"UPDATE accounts SET balance = balance + ? WHERE id = ?")) {
[Link](1, 1000); [Link](2, 1); // debit
[Link](1, 1000); [Link](2, 2); // credit
[Link]();
[Link]();
[Link](); // BOTH succeed → commit
[Link]("Transfer complete!");
} catch (SQLException e) {
[Link](); // ANY failure → rollback BOTH
[Link]("Transfer failed — rolled back!");
}
}
4.11 Statement vs PreparedStatement vs CallableStatement
Feature Statement PreparedStatement CallableStatement
SQL type Static SQL Parameterized SQL Stored Procedures
Precompiled? No Yes — faster for repeat Yes
SQL Injection risk High (never use with None — parameters None
user input) bound safely
Performance Slow if repeated Fast for repeat Fast
execution
Parameters None ? placeholders IN/OUT/INOUT params
4.12 ResultSet Methods
Method Returns Description
[Link]() boolean Move to next row; false if no more
[Link](col) int Get int column by name or index
[Link](col) String Get String column
Method Returns Description
[Link](col) double Get double column
[Link](col) Date Get SQL date
[Link](col) boolean Get boolean column
[Link](col) Object Get any column as Object
[Link]() boolean Check if last read column was NULL
4.13 Connecting to Non-conventional Databases
SQLite (Embedded — no server needed)
// Add SQLite JDBC dependency: [Link]:sqlite-jdbc
String url = "jdbc:sqlite:[Link]"; // creates file if not exists
try (Connection conn = [Link](url);
Statement stmt = [Link]()) {
[Link]("CREATE TABLE IF NOT EXISTS items(id INT, name TEXT)");
[Link]("INSERT INTO items VALUES(1,'Java Book')");
ResultSet rs = [Link]("SELECT * FROM items");
while([Link]()) [Link]([Link](1)+" "+[Link](2));
}
MongoDB (via MongoDB Java Driver — NoSQL)
// Add: [Link]:mongodb-driver-sync
import [Link].*;
import [Link];
MongoClient client = [Link]("mongodb://localhost:27017");
MongoDatabase db = [Link]("school");
MongoCollection<Document> col = [Link]("students");
// INSERT
Document doc = new Document("name", "Shivam")
.append("marks", 92)
.append("grade", "A");
[Link](doc);
// SELECT
for (Document d : [Link]()) {
[Link]([Link]("name") + ": " + [Link]("marks"));
}
Connection to Different DB URLs
Database JDBC URL Format Driver Class
MySQL jdbc:mysql://host:3306/dbname [Link]
PostgreSQL jdbc:postgresql://host:5432/dbname [Link]
SQLite jdbc:sqlite:/path/to/[Link] [Link]
Database JDBC URL Format Driver Class
Oracle jdbc:oracle:thin:@host:1521:sid [Link]
SQL Server jdbc:sqlserver:// [Link]
host:1433;databaseName=db verDriver
H2 (In-memory) jdbc:h2:mem:testdb [Link]
4.14 JDBC Best Practices
• Always use PreparedStatement for user input — prevents SQL Injection
• Always close resources in finally or use try-with-resources
• Use connection pooling (HikariCP, c3p0) for production — don't open/close per request
• Set autoCommit(false) for multi-step operations requiring atomicity
• Store DB credentials in config files or environment variables — never hardcode
• Use getOrDefault patterns when columns may be NULL; check [Link]()
4.15 Viva Questions – Unit IV
[Easy] What is JDBC?
Ans: Java Database Connectivity — a Java API ([Link]) that provides a standard way to connect Java
applications to relational databases.
[Easy] What are the 5 steps to use JDBC?
Ans: 1) Load driver. 2) Get Connection. 3) Create Statement. 4) Execute SQL. 5) Close resources.
[Medium] What is the difference between Statement and PreparedStatement?
Ans: Statement: static SQL, recompiled each time, SQL injection risk. PreparedStatement: parameterized
(? placeholders), precompiled, safe from SQL injection, faster for repeated execution.
[Easy] What is a ResultSet?
Ans: A table of data representing the result of a SELECT query. Use [Link]() to iterate rows;
[Link](), [Link]() to get column values.
[Medium] What are JDBC driver types?
Ans: Type 1: JDBC-ODBC bridge (deprecated). Type 2: Native API. Type 3: Network Protocol. Type 4:
Pure Java (Thin) — most common.
[Medium] What is auto-commit in JDBC?
Ans: By default, each SQL statement is committed immediately. Setting [Link](false) allows
multiple statements to form a transaction, committed with commit() or rolled back with rollback().
[Hard] What is SQL Injection and how does PreparedStatement prevent it?
Ans: SQL Injection: attacker inserts malicious SQL through user input. PreparedStatement binds
parameters separately — the input is never interpreted as SQL.
[Hard] What is connection pooling?
Ans: Maintaining a pool of pre-opened database connections to reuse them instead of creating a new
connection per request. Dramatically improves performance (HikariCP is popular).
[Hard] How do you connect to a non-relational database using Java?
Ans: For MongoDB: use MongoDB Java Driver (not JDBC). For SQLite: SQLite JDBC driver (Type 4).
Each DB has its own driver and connection API.
4.16 Coding Questions – Unit IV
Q1. Write a full CRUD application for a 'products' table (id, name, price, stock) using JDBC and
MySQL.
Hint: Create table; insert 3 products; select all; update price; delete one
Q2. Write a program to insert 100 students in batch using [Link]() and
executeBatch().
Hint: [Link](); [Link](); every 10 rows: [Link]()
Q3. Implement a bank transfer using JDBC transactions: debit account A, credit account B. Rollback
if either fails.
Hint: setAutoCommit(false); try: update+update+commit; catch: rollback
Q4. Write a program to connect to an SQLite database, create a table, insert 3 records, and display
them.
Hint: jdbc:sqlite:[Link]; no server needed
Q5. Search students by name (using LIKE) and display results formatted in a table.
Hint: PreparedStatement with 'SELECT * WHERE name LIKE ?'; [Link](1,'%'+name+'%')
⚡ Quick Reference Cheat Sheet
I/O Stream Selection Guide
If you need… Use…
Read/write text files line by line BufferedReader / BufferedWriter
Read/write binary files (images, audio) FileInputStream / FileOutputStream with byte buffer
Write/read Java primitives to file DataOutputStream / DataInputStream
Serialize Java objects to file ObjectOutputStream / ObjectInputStream
Formatted text output PrintWriter
Generics — Quick Rules
• class Box<T> — single type param; class Pair<K,V> — two params
• <T extends Number> — upper bound; T must be Number or subclass
• <? extends T> — wildcard, read from; <? super T> — wildcard, write to
• PECS: Producer Extends (read), Consumer Super (write)
• Type erasure: generics are compile-time only; runtime uses raw types
Thread Methods — Quick Ref
Method Key Behaviour
start() Creates new thread; calls run() asynchronously
run() Task code — never call directly (no new thread!)
sleep(ms) Pause; does NOT release lock
wait() Pause + RELEASE lock; must be in synchronized
notify() Wake one waiter; does NOT release lock until sync exits
join() Wait for another thread to finish
JDBC Execute Methods
Method Returns Use For
executeQuery(sql) ResultSet SELECT queries
executeUpdate(sql) int (rows affected) INSERT, UPDATE, DELETE, DDL
execute(sql) boolean Any SQL (true if ResultSet returned)
executeBatch() int[] (rows per Batch inserts/updates
statement)
Common Mistakes
• Calling [Link]() instead of [Link]() — no new thread created!
• Using Statement with user input — always use PreparedStatement
• Not closing JDBC resources — causes connection/cursor leaks
• wait()/notify() outside synchronized block — IllegalMonitorStateException
• Reading back DataInputStream in different order than written — corrupted data
• Not declaring serialVersionUID — deserialization fails after class change
• Using raw types (List instead of List<T>) — defeats generics purpose
• Acquiring locks in different order across threads — causes deadlock
Master the fundamentals, build something real, and you'll never forget them. 🚀