🏃‍♂️
Multithreading

Multithreading

Doing Many Things at Once
💡 Single thread एक अकेला runner है जो एक-एक करके सब काम करता है। Multithreading कई runners एक साथ अलग-अलग tracks पर दौड़ते हैं — काम जल्दी होता है!

Thread program का एक independent flow है। Normally Java एक thread (main) में चलता है।

Thread class extend करके या Runnable implement करके नए threads बना सकते हो, जो parallel काम करते हैं।

class MyThread extends Thread {
  public void run() { System.out.println("Running..."); }
}
new MyThread().start();
🏃‍♂️
Single thread एक अकेला runner है जो एक-एक करके सब काम करता है। Multithreading कई runners एक साथ अलग-अलग tracks पर दौड़ते हैं — काम जल्दी होता है!
1 / 3
⚡ झट से Recap
  • Thread = independent execution path
  • Parallel काम एक साथ होता है
  • synchronized से data safe रहता है
इस page में (4 subtopics)

Thread class extend करो और run() override करो — simple है लेकिन यह "extends" slot use कर लेता है (Java single inheritance है, इसलिए तुम्हारी class अब कुछ और extend नहीं कर सकती)।

या Runnable interface implement करो और उसे Thread को pass करो — यह better practice है क्योंकि class दूसरी भी extend कर सकती है, और behavior (Runnable — "क्या करना है") thread (Thread — "कैसे चलाना है") से अलग रहता है। Modern Java में Runnable approach ही ज़्यादा recommend होती है।

extends Threadimplements Runnable
दूसरी class extend कर सकते हो?नहींहाँ
Recommended?कमज़्यादा (best practice)
ExecutorService के साथ useमुश्किलआसान
class MyTask implements Runnable {
  public void run() { System.out.println("Running!"); }
}
Thread t = new Thread(new MyTask());
t.start();
⚠️Common Mistake: t.run() call करना और t.start() call करना बिल्कुल अलग है! run() सिर्फ एक normal method call है (same thread में चलेगा, कोई नया thread नहीं बनेगा)। start() ही actually नया thread बनाता है जो parallel में run() को execute करता है।

हर thread की priority होती है (1 से 10, default 5, setPriority() से change कर सकते हो) — JVM को एक "hint" देता है किस thread को ज़्यादा CPU time मिलना चाहिए (guarantee नहीं है, OS-dependent, कई OS इस hint को ignore भी कर सकते हैं)।

Daemon thread background service threads होते हैं (जैसे Garbage Collector खुद एक daemon thread है) — जब सारे non-daemon (normal) threads खत्म हो जाते हैं, JVM daemon threads की परवाह किए बिना exit हो जाता है। setDaemon(true) से किसी thread को daemon बनाया जा सकता है (start() से पहले call करना ज़रूरी है)।

Thread.sleep(ms) current thread को कुछ देर के लिए "pause" कर देता है — कोई दूसरा thread का wait नहीं कर रहा, बस अपना time pass कर रहा है (यह static method है, current thread पर ही असर करता है)।

t.join() एक thread को दूसरे thread (t) के *खत्म होने तक* wait करवाता है — जैसे main thread चाहता हो कि worker thread पहले अपना काम पूरा करे, तब ही आगे बढ़े। यह तब useful है जब result एक thread से दूसरे thread को चाहिए।

Thread worker = new Thread(() -> doWork());
worker.start();
worker.join(); // main thread yaha wait karega worker khatam hone tak
System.out.println("Worker done, ab aage badho");

जब multiple threads एक shared variable को simultaneously change करने की कोशिश करते हैं बिना proper synchronization के, result unpredictable हो जाता है — इसको "race condition" कहते हैं।

जैसे दो threads एक counter को ++ कर रहे हों: count++ actually 3 steps हैं (read current value, add 1, write back) — अगर दोनों threads एक साथ "read" कर लें पुरानी value, दोनों अपना-अपना increment लिखेंगे, लेकिन एक update "lost" हो जाएगा (final value expected से कम आएगी)।

// DANGEROUS without synchronization:
class Counter {
  int count = 0;
  void increment() { count++; } // NOT atomic! race condition risk
}
⚠️Common Mistake: count++ एक single, atomic operation नहीं है — यह read-modify-write है। Multi-threaded environment में इससे race condition हो सकती है। Fix के लिए synchronized या AtomicInteger use करो (अगला topic में detail)।