[Go to site: main page, start]

0% found this document useful (0 votes)
10 views2 pages

Java Threading & Multithreading Guide

Uploaded by

cinesynthmind
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)
10 views2 pages

Java Threading & Multithreading Guide

Uploaded by

cinesynthmind
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

Java Threading & Multithreading – Practice Sheet

Section A: Quick-Fire Conceptual Q&A;


Q: Process vs Thread?
Process: Independent execution unit with its own memory space. Thread: Lightweight execution
unit within a process, shares memory.

Q: Difference between Runnable and Thread class?


Thread: Subclassed to override run(). Runnable: Interface; can be shared by multiple threads.
Prefer Runnable for better design (avoids single inheritance).

Q: Daemon vs User thread?


User Thread: Runs until completion (e.g., main thread). Daemon Thread: Background thread (e.g.,
GC); JVM exits when only daemons remain.

Q: Synchronized vs Lock?
synchronized: Intrinsic lock, simple but limited. Lock (e.g., ReentrantLock): Explicit, fair/unfair mode,
tryLock(), interruptible, multiple conditions.

Q: ExecutorService vs Thread?
ExecutorService manages a thread pool, reuses threads. Better than manual thread management.

Q: Volatile vs Synchronized?
volatile: Guarantees visibility only. synchronized: Guarantees mutual exclusion + visibility.

Q: Difference between sleep(), wait(), join()?


sleep(ms): Pauses thread but does not release lock. wait(): Releases lock and waits for
notify()/notifyAll(). join(): Current thread waits until target thread finishes.

Q: Callable vs Runnable?
Runnable: run(), no return, no checked exceptions. Callable: call(), returns value, can throw
checked exceptions.

Section B: Scenario-Based Challenges


Q: Print numbers 1–10 using two threads (odd/even alternately).
Use shared monitor + wait/notify.

Q: Producer-Consumer problem.
Solve with BlockingQueue (ArrayBlockingQueue).

Q: Deadlock detection example.


Two threads holding different locks and waiting for each other.

Q: Implement thread-safe Singleton.


Use double-checked locking with volatile.

Section C: Hands-On Coding Drills


Q: Create a thread using Runnable
class Task implements Runnable { public void run() { [Link]("Running in " +
[Link]().getName()); } } public static void main(String[] args) { Thread t = new
Thread(new Task()); [Link](); }

Q: Producer-Consumer with BlockingQueue


BlockingQueue queue = new ArrayBlockingQueue<>(5); Runnable producer = () -> { for (int i=0;
i<10; i++) [Link](i); [Link](-1); }; Runnable consumer = () -> { while(true){ int
x=[Link](); if(x==-1) break; [Link]("Consumed "+x); } }; new
Thread(producer).start(); new Thread(consumer).start();

Q: Odd-Even threads printing


class Printer { private int number = 1; private final int limit = 10; private boolean odd = true;
synchronized void printOdd() throws InterruptedException { while (number <= limit) { while (!odd)
wait(); [Link]("Odd: " + number++); odd = false; notifyAll(); } } synchronized void
printEven() throws InterruptedException { while (number <= limit) { while (odd) wait();
[Link]("Even: " + number++); odd = true; notifyAll(); } } }

Q: Callable + Future example


ExecutorService ex = [Link](2); Future future = [Link](() -> {
[Link](500); return 42; }); [Link]([Link]()); [Link]();

Q: Thread-safe Singleton (Double-Checked Locking)


class Singleton { private static volatile Singleton instance; private Singleton() {} public static
Singleton getInstance() { if (instance == null) { synchronized ([Link]) { if (instance == null)
instance = new Singleton(); } } return instance; } }

Section D: Trick & Gotcha Questions


Q: What happens if you call run() instead of start() on a thread?
Runs in the same thread, no new thread is created.

Q: What happens if two threads call wait() but only one notify() is issued?
Only one thread wakes up. Use notifyAll() to wake all.

Q: Deadlock example
Object lock1 = new Object(), lock2 = new Object(); new Thread(() -> { synchronized(lock1){
synchronized(lock2){} } }).start(); new Thread(() -> { synchronized(lock2){ synchronized(lock1){} }
}).start(); // Deadlock possible.

Q: Is volatile enough for atomic operations like counter++?


No. counter++ is read-modify-write (not atomic). Use AtomicInteger or synchronized.

Common questions

Powered by AI

Using AtomicInteger is more suitable than volatile for incrementing a shared counter because the increment operation is read-modify-write and not atomic. AtomicInteger provides atomic methods like incrementAndGet() that handle synchronization and ensure thread-safe increment operations, which volatile cannot achieve alone .

Using the Runnable interface is preferred for better design because it avoids single inheritance limitations, allowing a class to implement Runnable while extending another class. Additionally, Runnable objects can be shared by multiple threads, whereas extending Thread means creating a new thread instance for each use .

The synchronized keyword provides a simple intrinsic lock mechanism that guarantees mutual exclusion but lacks flexibility. In contrast, the Lock interface, such as ReentrantLock, offers more sophisticated features like explicit locking, fair/unfair modes, tryLock(), and support for multiple conditions, making it more versatile for complex synchronization needs .

Deadlock can occur when two or more threads hold locks and wait for each other to release them, creating a cycle of dependencies with no resolution. A typical coding pattern leading to deadlock is when threads acquire multiple locks in different orders, causing circular wait conditions .

A process is an independent execution unit with its own memory space, while a thread is a lightweight execution unit within a process that shares memory with other threads in the same process .

sleep() pauses the thread for a defined time without releasing any locks. wait() releases the lock and allows other threads to execute while it waits for notify()/notifyAll(). join() causes the current thread to pause execution until the specified thread completes its execution .

Using notify() instead of notifyAll() can lead to situations where some threads remain blocked indefinitely if the notified thread does not resume the proper execution flow. This is particularly risky in scenarios where multiple threads are waiting for different conditions, as only one will wake up, potentially causing deadlocks or lost signals .

Daemon threads run in the background for tasks like garbage collection and do not prevent the JVM from exiting once all user threads have completed. In contrast, user threads are designed to run until they finish, and the JVM continues executing while there are any user threads running .

The volatile keyword ensures visibility of changes to a variable across threads but does not ensure atomicity or mutual exclusion. In contrast, synchronized provides both mutual exclusion and visibility, ensuring that only one thread can access the synchronized block or method at a time and subsequent thread reads the updated value .

Double-checked locking is used in Singleton patterns to minimize synchronization overhead by only locking the critical section when the Singleton instance is uninitialized. The volatile keyword ensures that changes to the instance variable are visible to all threads, preventing the Java memory model's instruction reordering that could result in improper object construction .

You might also like