Advantages and applications of CompletionService

1. Requirements description

There are many pictures on the homepage of a certain picture website, and the rendering time is long, which brings a poor user experience. To improve the user experience, the pictures need to be cached without waiting for all the pictures to be ready before rendering

2. Problem Analysis and Implementation

Obviously, we can think of acquiring pictures while rendering and operating in parallel. However, the acquisition time of each image is unpredictable, that is, the execution time of the task is inconsistent, some may be a few milliseconds, and some may be a few seconds. How can we render the image that is acquired first? Fortunately, CompletionService is suitable for this scenario: integrate the functions of Executor and BlockingQueue, submit Callable tasks to it for execution, and then obtain completed tasks similar to take and poll in the queue.

3. CompletionService source code analysis

public interface CompletionService<V> {
    
    
        Future<V> submit(Callable<V> task);

        Future<V> take() throws InterruptedException;

        Future<V> poll();

        ......
}

The only implementation class of CompletionService: ExecutorCompletionService. Create a BlockingQueue in the constructor to save the results. After the task is submitted, the task is packaged into QueueingFuture (a subclass of FutureTask). After the task is completed, the done method of QueueingFuture is called, and the result is put into BlockingQueue.

public class ExecutorCompletionService<V> implements CompletionService<V> {
    
    
    	private final BlockingQueue<Future<V>> completionQueue;

    	public ExecutorCompletionService(Executor executor) {
    
    
                if (executor == null)
                    throw new NullPointerException();
                this.executor = executor;
                this.aes = (executor instanceof AbstractExecutorService) ?
                    (AbstractExecutorService) executor : null;
                this.completionQueue = new LinkedBlockingQueue<Future<V>>();
        }

    	public Future<V> submit(Callable<V> task) {
    
    
                if (task == null) throw new NullPointerException();
                RunnableFuture<V> f = newTaskFor(task);
                executor.execute(new QueueingFuture(f)); // 任务包装成QueueingFuture
                return f;
        }

        private class QueueingFuture extends FutureTask<Void> {
    
    
                QueueingFuture(RunnableFuture<V> task) {
    
    
                    super(task, null);
                    this.task = task;
                }
                protected void done() {
    
     completionQueue.add(task); } // 任务完成后,调用done方法,放入队列
                private final Future<V> task;
        }

        public Future<V> take() throws InterruptedException {
    
    
                return completionQueue.take();
        }

        public Future<V> poll() {
    
    
                return completionQueue.poll();
        }
}

4. Code implementation

/**
 * 使用CompletionService实现页面渲染器
 */
public class Renderer {
    
    

        private ExecutorService executor;

        public Renderer(ExecutorService executor) {
    
    
                this.executor = executor;
        }

        public void renderPage(CharSequence source) {
    
    
                List<ImageInfo> info = scanImageInfo(source);
                CompletionService<ImageData> completionService = new ExecutorCompletionService<>(executor);

                for (final ImageInfo imageInfo : info) {
    
    
                        completionService.submit(() -> {
    
    
                                return imageInfo.downloadImage();
                        });
                }

                renderText(source);

                try {
    
    
                        for (int i = 0; i < info.size(); i++) {
    
    
                                Future<ImageData> future = completionService.take();
                                ImageData imageData = future.get();
                                renderImage(imageData);
                        }
                } catch (InterruptedException e) {
    
    
                        Thread.currentThread().interrupt();
                } catch (ExecutionException e) {
    
    
                        e.printStackTrace();
                }
        }
}

Welcome to pay attention to the official account algorithm niche

Guess you like

Origin blog.csdn.net/SJshenjian/article/details/130302470