Site Search:

TimeBudget.java

TimeBudget.java simulates the webpage of a travel agent. The agent needs to fetch the airline prices from different companies within a time limit, then displays the quotes with price order. Fetching the bid from one company is independent from fetching the bid from another. So multiple biding tasks are submitted to an ExecutorService with invokeAll (List<Future<TravelQuote>> futures = exec.invokeAll(tasks, time, unit);), and a list of Future objects are returned for retrieving the TravelQuote returned from different companies. InvokeAll has a timeout, so if a company didn't response quick enough,  f.get() will throw CancellationException, which result in a null quote to be added.

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

/**
 * QuoteTask
 * <p/>
 * Requesting travel quotes under a time budget
 */
public class TimeBudget {
    private static ExecutorService exec = Executors.newCachedThreadPool();
    
    public static void main(String args[]) {
        TimeBudget tb = new TimeBudget();
        Set<TravelCompany> companies = new HashSet<>();
        companies.add(travelInfo -> new TravelQuoteImpl(1000, "aaa"));
        companies.add(travelInfo -> new TravelQuoteImpl(1048, "bbb"));
        companies.add(travelInfo -> {Thread.sleep(2000);return new TravelQuoteImpl(2489, "ccc");});
        companies.add(travelInfo -> new TravelQuoteImpl(876, "xyzcode"));
        companies.add(travelInfo -> new TravelQuoteImpl(1209, "xyznetwork"));
        try {
            List<TravelQuote> quotes = tb.getRankedTravelQuotes(
                    () -> "07-03-2017,NYC,Boston", 
                    companies, 
                    Comparator.nullsFirst(Comparator.comparingInt(TravelQuote::getPrice)), 
                    1, TimeUnit.SECONDS);
            quotes.stream().filter(i -> i != null).map(TravelQuote::getQuote).forEach(System.out::println);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public List<TravelQuote> getRankedTravelQuotes(TravelInfo travelInfo, Set<TravelCompany> companies,
                                                   Comparator<TravelQuote> ranking, long time, TimeUnit unit)
            throws InterruptedException {
        List<QuoteTask> tasks = new ArrayList<QuoteTask>();
        for (TravelCompany company : companies)
            tasks.add(new QuoteTask(company, travelInfo));

        List<Future<TravelQuote>> futures = exec.invokeAll(tasks, time, unit); //time out

        List<TravelQuote> quotes =
                new ArrayList<TravelQuote>(tasks.size());
        Iterator<QuoteTask> taskIter = tasks.iterator();
        for (Future<TravelQuote> f : futures) {
            QuoteTask task = taskIter.next();
            try {
                quotes.add(f.get());
            } catch (ExecutionException e) {
                quotes.add(task.getFailureQuote(e.getCause()));
            } catch (CancellationException e) {
                quotes.add(task.getTimeoutQuote(e));
            }
        }
        exec.shutdown();
        exec.awaitTermination(10, TimeUnit.SECONDS);

        Collections.sort(quotes, ranking);
        return quotes;
    }

}

class QuoteTask implements Callable<TravelQuote> {
    private final TravelCompany company;
    private final TravelInfo travelInfo;

    public QuoteTask(TravelCompany company, TravelInfo travelInfo) {
        this.company = company;
        this.travelInfo = travelInfo;
    }

    TravelQuote getFailureQuote(Throwable t) {
        return null;
    }

    TravelQuote getTimeoutQuote(CancellationException e) {
        return null;
    }

    public TravelQuote call() throws Exception {
        return company.solicitQuote(travelInfo);
    }
}

interface TravelCompany {
    TravelQuote solicitQuote(TravelInfo travelInfo) throws Exception;
}

class TravelQuoteImpl implements TravelQuote {
    private int price = 0;
    private String name;
    TravelQuoteImpl(int price, String name) {
        this.price = price;
        this.name = name;
    }
    @Override
    public String getQuote() {
        return name + ":" + this.price;
    }
    @Override
    public int getPrice() {
        return price;
    }
}

interface TravelQuote {
    String getQuote();
    int getPrice();
}

interface TravelInfo {
    String getDateAndCities();
}
Concurrency>javac TimeBudget.java 
Concurrency>date; java TimeBudget; date
Sat Jul 15 23:45:13 EDT 2017
xyzcode:876
aaa:1000
bbb:1048
xyznetwork:1209
Sat Jul 15 23:45:14 EDT 2017

Concurrency>