Site Search:

Renderer.java

The following example simulates a web browser rendering webpages with both text and images. A CompletionService is used to facilitate concurrent downloading of images. CompletionService combines the functionality of an Executor and a BlockingQueue. The computation is delegated to an Executor, you can submit Callable tasks to it for the Executor to execute and use take and poll to retrieve completed results. Comparing to FutureRenderer, Render is faster, because it uses 6 instead of 2 threads to rendering the page -- the main thread renders text, 5 executor worker threads download the images. And by fetching results from the CompletionService and rendering each image as soon as it is available, the page is more responsive.


Concurrency>cat Renderer.java 
import java.util.*;
import java.util.concurrent.*;

/**
 * Renderer
 * <p/>
 * Using CompletionService to render page elements as they become available
 */
public abstract class Renderer {
    private final ExecutorService executor;

    Renderer(ExecutorService executor) {
        this.executor = executor;
    }
    
    public static void main(String[] args) {
        Renderer futureRenderer = new Renderer(Executors.newCachedThreadPool()) {
            @Override
            void renderText(CharSequence s) {
                try {
                    Thread.sleep(2000);
                    System.out.println(Thread.currentThread().toString() + " renders text finished.");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("rendering text: " + s);
            }

            @Override
            List<ImageInfo> scanForImageInfo(CharSequence s) {
                List<ImageInfo> imageInfos = new ArrayList<>();
                for(int i = 0; i < 5; i++) {
                    imageInfos.add(new ImageInfo() {
                        @Override
                        public ImageData downloadImage() {
                            try {
                                Thread.sleep(2000);
                                System.out.println(Thread.currentThread().toString() + " downloads image complete.");
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            return new ImageData() {};
                        }
                        
                    });
                }
                return imageInfos;
            }

            @Override
            void renderImage(ImageData i) {
                System.out.println("rendering image: " + i.toString());
            }
        };
        
        futureRenderer.renderPage("page HTML code here");
        
    }

    void renderPage(CharSequence source) {
        final List<ImageInfo> info = scanForImageInfo(source);
        CompletionService<ImageData> completionService =
                new ExecutorCompletionService<ImageData>(executor);
        for (final ImageInfo imageInfo : info)
            completionService.submit(() -> imageInfo.downloadImage());

        renderText(source);
        renderText(source);

        try {
            for (int t = 0, n = info.size(); t < n; t++) {
                Future<ImageData> f = completionService.take();
                ImageData imageData = f.get();
                renderImage(imageData);
            }
            executor.shutdown();
            executor.awaitTermination(10, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }
    }

    interface ImageData {
    }

    interface ImageInfo {
        ImageData downloadImage();
    }

    abstract void renderText(CharSequence s);

    abstract List<ImageInfo> scanForImageInfo(CharSequence s);

    abstract void renderImage(ImageData i);

}
Concurrency>javac Renderer.java 
Concurrency>date; java Renderer; date
Sat Jul 15 17:24:45 EDT 2017
Thread[main,5,main] renders text finished.
rendering text: page HTML code here
Thread[pool-1-thread-5,5,main] downloads image complete.
Thread[pool-1-thread-4,5,main] downloads image complete.
Thread[pool-1-thread-1,5,main] downloads image complete.
Thread[pool-1-thread-2,5,main] downloads image complete.
Thread[pool-1-thread-3,5,main] downloads image complete.
Thread[main,5,main] renders text finished.
rendering text: page HTML code here
rendering image: Renderer$1$1$1@2a84aee7
rendering image: Renderer$1$1$1@a09ee92
rendering image: Renderer$1$1$1@30f39991
rendering image: Renderer$1$1$1@452b3a41
rendering image: Renderer$1$1$1@4a574795
Sat Jul 15 17:24:49 EDT 2017

Concurrency>