सवाल
आप जावा 8 में एक उचित पृष्ठभूमि लोडर कैसे बना सकते हैं? शर्तें:
- डेटा को पृष्ठभूमि में लोड किया जाना चाहिए
- लोड करने के बाद डेटा प्रदर्शित किया जाना चाहिए
- जब डेटा लोड किया जाता है तो कोई और अनुरोध स्वीकार नहीं किया जाना चाहिए
- यदि डेटा के लोड होने के समय अनुरोध थे, तो एक निश्चित समय समाप्ति के बाद एक और लोडिंग शेड्यूल किया जाना चाहिए (जैसे 5 सेकंड)
इसका उद्देश्य उदाहरण के लिए पुनः लोड अनुरोधों को स्वीकार करना है, लेकिन डेटाबेस अनुरोधों से भरा नहीं है।
MCVE
यहाँ एक MCVE है। इसमें एक बैकग्राउंड टास्क होता है जो केवल 2 सेकंड के लिए Thread.sleep को लोड करके लोडिंग को सिमुलेट करता है। प्रत्येक सेकंड में कार्य निर्धारित होता है जो स्वाभाविक रूप से पृष्ठभूमि लोडिंग कार्यों के ओवरलैप की ओर जाता है, जिसे टाला जाना चाहिए।
public class LoadInBackgroundExample {
/**
* A simple background task which should perform the data loading operation. In this minimal example it simply invokes Thread.sleep
*/
public static class BackgroundTask implements Runnable {
private int id;
public BackgroundTask(int id) {
this.id = id;
}
/**
* Sleep for a given amount of time to simulate loading.
*/
@Override
public void run() {
try {
System.out.println("Start #" + id + ": " + Thread.currentThread());
long sleepTime = 2000;
Thread.sleep( sleepTime);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("Finish #" + id + ": " + Thread.currentThread());
}
}
}
/**
* CompletableFuture which simulates loading and showing data.
* @param taskId Identifier of the current task
*/
public static void loadInBackground( int taskId) {
// create the loading task
BackgroundTask backgroundTask = new BackgroundTask( taskId);
// "load" the data asynchronously
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(new Supplier<String>() {
@Override
public String get() {
CompletableFuture<Void> future = CompletableFuture.runAsync(backgroundTask);
try {
future.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
return "task " + backgroundTask.id;
}
});
// display the data after they are loaded
CompletableFuture<Void> future = completableFuture.thenAccept(x -> {
System.out.println( "Background task finished:" + x);
});
}
public static void main(String[] args) {
// runnable which invokes the background loader every second
Runnable trigger = new Runnable() {
int taskId = 0;
public void run() {
loadInBackground( taskId++);
}
};
// create scheduler
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
ScheduledFuture<?> beeperHandle = scheduler.scheduleAtFixedRate(trigger, 0, 1, TimeUnit.SECONDS);
// cancel the scheudler and the application after 10 seconds
scheduler.schedule(() -> beeperHandle.cancel(true), 10, TimeUnit.SECONDS);
try {
beeperHandle.get();
} catch (Throwable th) {
}
System.out.println( "Cancelled");
System.exit(0);
}
}
आउटपुट यह है:
Start #0: Thread[ForkJoinPool.commonPool-worker-2,5,main]
Start #1: Thread[ForkJoinPool.commonPool-worker-4,5,main]
Start #2: Thread[ForkJoinPool.commonPool-worker-6,5,main]
Finish #0: Thread[ForkJoinPool.commonPool-worker-2,5,main]
Background task finished:task 0
Finish #1: Thread[ForkJoinPool.commonPool-worker-4,5,main]
Background task finished:task 1
Start #3: Thread[ForkJoinPool.commonPool-worker-4,5,main]
Finish #2: Thread[ForkJoinPool.commonPool-worker-6,5,main]
Background task finished:task 2
Start #4: Thread[ForkJoinPool.commonPool-worker-6,5,main]
Start #5: Thread[ForkJoinPool.commonPool-worker-2,5,main]
Finish #3: Thread[ForkJoinPool.commonPool-worker-4,5,main]
Background task finished:task 3
Start #6: Thread[ForkJoinPool.commonPool-worker-4,5,main]
Finish #4: Thread[ForkJoinPool.commonPool-worker-6,5,main]
Background task finished:task 4
Finish #5: Thread[ForkJoinPool.commonPool-worker-2,5,main]
Background task finished:task 5
Start #7: Thread[ForkJoinPool.commonPool-worker-2,5,main]
Finish #6: Thread[ForkJoinPool.commonPool-worker-4,5,main]
Start #8: Thread[ForkJoinPool.commonPool-worker-6,5,main]
Background task finished:task 6
Start #9: Thread[ForkJoinPool.commonPool-worker-4,5,main]
Finish #7: Thread[ForkJoinPool.commonPool-worker-2,5,main]
Background task finished:task 7
Start #10: Thread[ForkJoinPool.commonPool-worker-2,5,main]
Finish #8: Thread[ForkJoinPool.commonPool-worker-6,5,main]
Background task finished:task 8
Cancelled
लक्ष्य # 1 और # 2 छोड़ दिया गया है, क्योंकि # 0 अभी भी चल रहा है।
मुसीबत
आप अवरुद्ध तंत्र को ठीक से कहाँ सेट करते हैं? क्या सिंक्रनाइज़ेशन का उपयोग किया जाना चाहिए? या कुछ AtomicBoolean
? और यदि हां, तो क्या यह get()
विधि के अंदर होना चाहिए या कहीं और?
ExecutorService
1 के थ्रेड पूल आकार के साथ विचार किया है?
BlockingQueue
?