Java 5 में पेश किया गया Future<T> इंटरफेस एसिंक्रोनस गणना के परिणाम का प्रतिनिधित्व करता है। Java 8 ने CompletableFuture<T> जोड़ा जो Future<T> को लागू करता है और शक्तिशाली संयोजन क्षमताएं प्रदान करता है।
मुख्य अंतर अवलोकन
| विशेषता | Future<T> | CompletableFuture<T> |
|---|---|---|
| ब्लॉकिंग get() | हां - get() ब्लॉक करता है | वैकल्पिक - गैर-ब्लॉकिंग चेनिंग |
| कॉलबैक/चेनिंग | नहीं | हां - thenApply, thenAccept, thenCompose |
| कई Futures संयोजित करें | मैन्युअल, जटिल | allOf, anyOf, thenCombine |
| असाधारण संचालन | केवल get() पर | exceptionally, handle, whenComplete |
| मैन्युअल पूर्णता | नहीं (केवल ExecutorService के माध्यम से) | हां - complete(), completeExceptionally() |
| इंटरफेस | Future | Future + CompletionStage |
Future की सीमाएं
// Future के साथ समस्या: ब्लॉकिंग get()
ExecutorService executor = Executors.newFixedThreadPool(2);
Future future1 = executor.submit(() -> {
Thread.sleep(1000);
return 10;
});
Future future2 = executor.submit(() -> {
Thread.sleep(1000);
return 20;
});
// परिणामों को संयोजित करने के लिए - दोनों get() पर ब्लॉक करना होगा!
int result = future1.get() + future2.get(); // 2 सेकंड ब्लॉक करता है
// कोई तरीका नहीं कहने का: "जब दोनों पूरे हों, तो उन्हें जोड़ें"
CompletableFuture समाधान
// गैर-ब्लॉकिंग चेनिंग
CompletableFuture cf1 = CompletableFuture.supplyAsync(() -> {
Thread.sleep(1000);
return 10;
});
CompletableFuture cf2 = CompletableFuture.supplyAsync(() -> {
Thread.sleep(1000);
return 20;
});
// समानांतर निष्पादन, फिर संयोजन - कोई ब्लॉकिंग नहीं!
CompletableFuture combined = cf1.thenCombine(cf2, (a, b) -> a + b);
// बाद में परिणाम प्राप्त करें (या जारी रखें चेनिंग)
combined.thenAccept(sum -> System.out.println("योग: " + sum)); // 30 प्रिंट करता है
// मुख्य थ्रेड अन्य काम कर सकता है
System.out.println("मुख्य थ्रेड मुक्त है!");
पूर्ण उदाहरण: मूल लेख से
import java.util.function.Supplier;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class CompletableFutureTest {
public static void main(String args[]) throws ExecutionException, InterruptedException {
Calculator calc = new Calculator(4, 7);
// एसिंक्रोनस सप्लाई
CompletableFuture future = CompletableFuture.supplyAsync(calc);
// गैर-ब्लॉकिंग कॉलबैक
future.thenAccept(result -> {
System.out.println("परिणाम: " + result); // 3 सेकंड बाद प्रिंट होता है
});
System.out.println("CompletableFutureTest End...."); // तुरंत प्रिंट होता है
// मुख्य थ्रेड को जीवित रखें ताकि डेमॉन थ्रेड पूरा हो सके
Thread.sleep(10000);
}
}
class Calculator implements Supplier {
private int x, y;
public Calculator(int x, int y) { this.x = x; this.y = y; }
@Override
public Integer get() {
try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); }
return x + y; // 11 लौटाता है
}
}
आउटपुट:
CompletableFutureTest End.... 11
CompletableFuture मुख्य मेथड्स
परिवर्तन (Transformation)
// thenApply: परिणाम बदलें, नया CompletableFuture लौटाएं
CompletableFuture strFuture = future.thenApply(i -> "परिणाम: " + i);
// thenCompose: दूसरा एसिंक्रोनस ऑपरेशन चेन करें (फ्लैटमैप)
CompletableFuture chained = future.thenCompose(i -> fetchDetailsAsync(i));
उपभोग (Consumption)
// thenAccept: परिणाम का उपभोग करें, कुछ न लौटाएं (void)
future.thenAccept(System.out::println);
// thenRun: परिणाम की अनदेखी करें, बस एक्शन चलाएं
future.thenRun(() -> System.out.println("किया!"));
संयोजन (Combination)
// thenCombine: दो स्वतंत्र futures संयोजित करें
cf1.thenCombine(cf2, (a, b) -> a + b)
// allOf: सभी पूरे होने की प्रतीक्षा करें (कोई परिणाम नहीं)
CompletableFuture all = CompletableFuture.allOf(cf1, cf2, cf3);
all.thenRun(() -> System.out.println("सभी पूरे!"));
// anyOf: किसी एक के पूरा होने की प्रतीक्षा करें
CompletableFuture
त्रुटि संचालन
// exceptionally: त्रुटि से उबरें
future.exceptionally(ex -> {
System.err.println("त्रुटि: " + ex.getMessage());
return -1; // डिफ़ॉल्ट मान
});
// handle: सफलता और विफलता दोनों संभालें
future.handle((result, ex) -> {
if (ex != null) return "विफल: " + ex.getMessage();
return "सफल: " + result;
});
// whenComplete: पूरा होने पर साइड इफेक्ट
future.whenComplete((result, ex) -> {
if (ex != null) ex.printStackTrace();
else System.out.println("पूर्ण: " + result);
});
मैन्युअल पूर्णता
// प्रोग्रामेटिक रूप से CompletableFuture बनाएं और पूरा करें
CompletableFuture manual = new CompletableFuture<>();
// बाद में किसी अन्य थ्रेड में...
manual.complete("हैलो वर्ल्ड"); // या
manual.completeExceptionally(new RuntimeException("कुछ गलत हुआ"));
// उपभोक्ता इसे सामान्य Future की तरह उपयोग करते हैं
manual.thenAccept(System.out::println);
सर्वोत्तम अभ्यास
- डिफ़ॉल्ट एक्जीक्यूटर से बचें:
supplyAsync(() -> ..., customExecutor)का उपयोग करें - अपवादों को संभालें: हमेशा
.exceptionally()या.handle()जोड़ें - ब्लॉकिंग से बचें:
get()/join()के बजाय चेनिंग का उपयोग करें - रद्दीकरण:
cancel(true)इंटरप्ट करता है;CompletionExceptionफेंक सकता है - CompletionStage: लचीलेपन के लिए
CompletableFutureके बजाय इस इंटरफेस के लिए प्रोग्राम करें
कब क्या उपयोग करें
- Future: सरल एसिंक्रोनस कार्य, लीगेसी कोड, जब ब्लॉकिंग स्वीकार्य हो
- CompletableFuture: जटिल वर्कफ्लो, समानांतर संयोजन, रिएक्टिव पैटर्न, आधुनिक Java एप्लिकेशन