Site Search:

FutureRenderer.java

The following program simulates a better web browser rendering a webpage with both text and images. The text rendering takes 2 seconds each and the image downloading takes 2 seconds each. It is better than single threaded version because it uses 2 threads instead of 1 to render the page: while the main thread is rendering text, the image downloading is running concurrently by another thread. The browser is also smarter -- instead of rendering text and images with the order they are encountered in the HTML, we can render the text first, leaving some spaceholoer for the images for later rendering once they are available.



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

/**
 * FutureRenderer
 * <p/>
 * Waiting for image download with \Future
 */
public abstract class FutureRenderer {
    private final ExecutorService executor = Executors.newCachedThreadPool();
    
    public static void main(String[] args) {
        FutureRenderer futureRenderer = new FutureRenderer() {

            @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> imageInfos = scanForImageInfo(source);

        Future<List<ImageData>> future = executor.submit(() -> {
            List<ImageData> result = new ArrayList<ImageData>();
            for (ImageInfo imageInfo : imageInfos)
                result.add(imageInfo.downloadImage());
            return result;
        });
        renderText(source);
        renderText(source);

        try {
            List<ImageData> imageData = future.get();
            for (ImageData data : imageData)
                renderImage(data);
        } catch (InterruptedException e) {
            // Re-assert the thread's interrupted status
            Thread.currentThread().interrupt();
            // We don't need the result, so cancel the task too
            future.cancel(true);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }
        
        executor.shutdown();
        try {
            executor.awaitTermination(10, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    interface ImageData {
    }

    interface ImageInfo {
        ImageData downloadImage();
    }

    abstract void renderText(CharSequence s);

    abstract List<ImageInfo> scanForImageInfo(CharSequence s);

    abstract void renderImage(ImageData i);
}
Concurrency>javac FutureRenderer.java 
Concurrency>date; java FutureRenderer; date
Sat Jul 15 16:37:23 EDT 2017
Thread[pool-1-thread-1,5,main] downloads image complete.
Thread[main,5,main] renders text finished.
rendering text: page HTML code here
Thread[main,5,main] renders text finished.
rendering text: page HTML code here
Thread[pool-1-thread-1,5,main] downloads image complete.
Thread[pool-1-thread-1,5,main] downloads image complete.
Thread[pool-1-thread-1,5,main] downloads image complete.
Thread[pool-1-thread-1,5,main] downloads image complete.
rendering image: FutureRenderer$1$1$1@2ff4acd0
rendering image: FutureRenderer$1$1$1@54bedef2
rendering image: FutureRenderer$1$1$1@5caf905d
rendering image: FutureRenderer$1$1$1@27716f4
rendering image: FutureRenderer$1$1$1@8efb846
Sat Jul 15 16:37:34 EDT 2017
Concurrency>