← Back to Advanced Java Course | Chapter 11: Advanced & Security | Lesson 16 of 19

Java Interview के Advanced सवाल

ये threads और memory जैसे topics पर मुश्किल सवाल हैं जो advanced Java interviews में आते हैं। इनका अभ्यास करना किसी performance से पहले rehearsal करने जैसा है।

Volatile vs. Atomic

volatile keyword किसी variable के लिए memory visibility की गारंटी देता है -- हर thread उसकी current value को किसी संभावित-stale per-thread cache से नहीं बल्कि सीधे पढ़ता है -- लेकिन यह increment जैसे compound operations को atomic नहीं बनाता। Atomic classes आगे जाती हैं, असली operation को भी (CAS के ज़रिए) atomic होने की गारंटी देते हुए।

उदाहरण: Volatile vs. Atomic

java
import java.util.concurrent.atomic.AtomicInteger;
public class Main {
	static volatile boolean flag = false; // guarantees visibility, not atomicity of compound ops
	static AtomicInteger counter = new AtomicInteger(0); // guarantees the operation itself is atomic
	public static void main(String[] args) {
		flag = true;
		counter.incrementAndGet();
		System.out.println(flag + " " + counter.get());
	}
}

Optimistic vs. Pessimistic Locking

Pessimistic locking मान लेता है कि conflicts होंगे और एक thread के किसी resource को पकड़े रहते समय दूसरे threads को उसे छूने से रोकता है। Optimistic locking मानता है कि conflicts दुर्लभ हैं, threads को बिना lock किए आगे बढ़ने देता है, और इसके बजाय अगर कोई conflicting modification असल में हुई हो तो उसे detect और retry करने के लिए एक atomic compare-and-swap loop उपयोग करता है।

उदाहरण: Optimistic vs. Pessimistic Locking

java
import java.util.concurrent.atomic.AtomicInteger;
public class Main {
	static final Object pessimisticLock = new Object();
	static AtomicInteger optimisticValue = new AtomicInteger(0);
	public static void main(String[] args) {
		synchronized (pessimisticLock) { // blocks other threads while held
			System.out.println("Pessimistic: locked");
		}
		int current;
		do {
			current = optimisticValue.get();
		} while (!optimisticValue.compareAndSet(current, current + 1)); // retries instead of blocking
		System.out.println("Optimistic: " + optimisticValue.get());
	}
}

ThreadLocal Memory

ThreadLocal आपको एक variable इस तरह store करने देता है कि इसे access करने वाला हर thread अपनी बिल्कुल स्वतंत्र copy देखे, बजाय threads में share होने वाली एक value के। यह per-thread state के लिए multi-threaded data leaks से बचने का एक आम तरीका है, जैसे कोई request context या formatter instance।

उदाहरण: ThreadLocal Memory

java
public class Main {
	static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 0);
	public static void main(String[] args) throws InterruptedException {
		threadLocal.set(42); // only visible to this thread
		Thread other = new Thread(() -> System.out.println("Other thread sees: " + threadLocal.get()));
		other.start();
		other.join();
		System.out.println("Main thread sees: " + threadLocal.get());
	}
}

Safe Serialization

deserialization को malicious input के खिलाफ सुरक्षित करने के लिए, किसी object की फिर से बनी state को भरोसा करने से पहले एक custom readObject() method के अंदर validate करें, या serialPersistentFields के ज़रिए यह सीमित करें कि कौन से fields serialization में शामिल हों, बजाय जो भी bytes आएं उन पर अंधाधुंध भरोसा करने के।

उदाहरण: Safe Serialization

java
import java.io.*;
public class Main {
	static class User implements Serializable {
		int age;
		private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
			in.defaultReadObject();
			if (age < 0) throw new InvalidObjectException("age cannot be negative"); // validate before trusting
		}
	}
	public static void main(String[] args) {
		System.out.println("readObject() validates reconstructed state before trusting it");
	}
}

Dynamic Method Dispatch

Dynamic Method Dispatch वह mechanism है जो यह तय करता है कि runtime पर कौन सा overridden method implementation असल में चलता है, reference के declared (static) type के बजाय object के असली (dynamic) type के आधार पर -- यह वह core mechanism है जो Java में runtime polymorphism को काम करने देता है।

उदाहरण: Dynamic Method Dispatch

java
public class Main {
	static class Animal {
		String sound() { return "..."; }
	}
	static class Dog extends Animal {
		String sound() { return "Woof"; } // overridden implementation
	}
	public static void main(String[] args) {
		Animal a = new Dog(); // declared type Animal, real type Dog
		System.out.println(a.sound()); // resolved at runtime based on the real type
	}
}
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
आम गलतियां
  1. यह सोचना कि volatile count++ को सुरक्षित बनाता है, जबकि यह सिर्फ visibility देता है और read-modify-write अब भी atomic नहीं है; AtomicInteger का उपयोग करें।
  2. किसी thread pool में remove() call किए बिना ThreadLocal का उपयोग करना, जिससे values reused threads से जुड़ी रहती हैं और leak हो सकती हैं।
  3. यह उम्मीद करना कि dynamic dispatch fields के लिए काम करता है, जबकि सिर्फ overridden methods runtime type उपयोग करते हैं जबकि fields reference type उपयोग करते हैं।

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.