Site Search:

RenderWithTimeBudget.java

The following example simulates a webpage with advertizement. While the main thread is rendering page body, a worker thread from ExecutorService is processing FetchAdTask. After main thread finish rendering page body, it get the Ad via ad = f.get(timeLeft, NANOSECONDS);. FetchAdTask takes 1 second to finish. If rendering page body finished in less than 1 second, the f.get(timeLeft, NANOSECONDS)Times out and FetchAdTask is canceled (f.cancel(true);). Otherwise, f.get(timeLeft, NANOSECONDS) returns the returned Ad from worker thread.


Concurrency>cat RenderWithTimeBudget.java 
import java.util.concurrent.*;
import static java.util.concurrent.TimeUnit.NANOSECONDS;

/**
 * RenderWithTimeBudget
 *
 * Fetching an advertisement with a time budget
 */
public class RenderWithTimeBudget {
    private static final Ad DEFAULT_AD = new Ad("DefaultAd");
    private static final long TIME_BUDGET = 1000;
    private static final ExecutorService exec = Executors.newCachedThreadPool();
    
    public static void main(String ... args) {
        RenderWithTimeBudget rwtb = new RenderWithTimeBudget();
        Page page;
        try {
            page = rwtb.renderPageWithAd(0);
            System.out.println(page.getAd().AdStr + "\n" +page.toString());
            
            page = rwtb.renderPageWithAd(3000);
            System.out.println(page.getAd().AdStr + "\n" +page.toString());
            exec.shutdown();
            exec.awaitTermination(10, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
    }

    Page renderPageWithAd(long delay) throws InterruptedException {
        long endNanos = System.nanoTime() + TIME_BUDGET;
        Future<Ad> f = exec.submit(new FetchAdTask());
        // Render the page while waiting for the ad
        Page page = renderPageBody();
        Thread.sleep(delay);
        Ad ad;
        try {
            // Only wait for the remaining time budget
            long timeLeft = endNanos - System.nanoTime();
            ad = f.get(timeLeft, NANOSECONDS);
        } catch (ExecutionException e) {
            ad = DEFAULT_AD;
        } catch (TimeoutException e) {
            ad = DEFAULT_AD;
            f.cancel(true);
        }
        page.setAd(ad);
        return page;
    }

    Page renderPageBody() { return new Page(); }


    static class Ad {
        String AdStr = "";
        Ad(String ad) {
            AdStr = ad;
        }
    }

    static class Page {
        Ad ad;
        public void setAd(Ad ad) {this.ad = ad; }
        public Ad getAd() {return ad;}
    }

    static class FetchAdTask implements Callable<Ad> {
        public Ad call() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                System.out.println("interrupted when cancel is called");
                Thread.currentThread().interrupt();
            }
            return new Ad("FetchedAd");
        }
    }
}
Concurrency>javac RenderWithTimeBudget.java 
Concurrency>java RenderWithTimeBudget
interrupted when cancel is called
DefaultAd
RenderWithTimeBudget$Page@42a57993
FetchedAd
RenderWithTimeBudget$Page@75b84c92

Concurrency>