Google Guava Concurrent Slides
Google Guava Concurrent Slides
concurrent
The Guava Team com.google.common.collect com.google.common.util.concurrent java.util.concurrent Effective Java (concurrency is in chapter 10) Java Concurrency in Practice
the linked doc s and books also have advic e about Java c onc urrenc y (general princ iples, java.util.c onc urrent) note: some slides refer to methods that have not yet been released (listeningDec orator, Futures.allAsList/suc c essfulAsList). We expec t to release these in Guava 10 in July
collect
Immutable* ConcurrentHashMultiset Multimaps.synchronizedMultimap MapMaker
before getting to util.c onc urrent, touc h on our other pac kages we keep c onc urrenc y in mind in our other pac kages
collect: Immutable*
whenever possible, for various reasons
use them. linked doc has advantages as well as some tradeoffs one of many reason to use them: thread safety immutable in the thread-safe sense many other c lasses without "Immutable" in the name are immutable (unlike JDK SimpleDateFormat): CharMatc her, Splitter
collect: ConcurrentHashMultiset
Multiset<K> Map<K, Integer> with extra methods and optional thread-safety Map<String, Integer> map = newHashMap(); for (StatsProto proto : protos) { String host = proto.getHost(); if (!map.containsKey(host)) { map.put(host, 1); } else { map.put(host, map.get(host) + 1); } }
c ode c ounts number of times eac h host appears in a proto map from element type to number of oc c urrenc es
collect: ConcurrentHashMultiset
Multiset<K> Map<K, Integer> with extra methods and optional thread-safety Multiset<String> multiset = HashMultiset.create(); for (StatsProto proto : protos) { multiset.add(proto.getHost()); } NumericMap (someday) prefer immutable
e.g., c ount number of queries to eac h shard Numeric Map to support long, double for, e.g., total nanosec onds spent in an operation sometimes need modifiability, e.g., stats (probably from different threads, therefore c onc urrenc y)
collect: Multimaps.synchronizedMultimap
Multimap<K, V> Map<K, Collection<V>> with extra methods and optional thread-safety Map<String, List<StatsProto>> map = newHashMap(); for (StatsProto proto : protos) { String host = proto.getHost(); if (!map.containsKey(host)) { map.put(host, new ArrayList<StatsProto>()); } map.get(host).add(proto); }
c ode indexes protos by host
collect: Multimaps.synchronizedMultimap
Multimap<K, V> Map<K, Collection<V>> with extra methods and optional thread-safety Multimap<String, StatsProto> multimap = ArrayListMultimap.create(); for (StatsProto proto : protos) { multimap.put(proto.getHost(), proto); } synchronized performs better than our internal wait-free equivalent prefer immutable
this partic ular c ode c ould use Multimaps.index() sync hronization espec ially painful with "c hec k then ac t" nec essary for the first item (multiset and multimap both)
collect: MapMaker
slides to come in a few months
build c onc urrent maps and c ac hes
collect: MapMaker
slides to come in a few months
private final ConcurrentMap<String, Feed> feedCache = new MapMaker() .expireAfterWrite(2, MINUTES) .maximumSize(100), .makeMap();
on-demand c omputation with c omputing maps. with a "normal" c ac he, you must look in the c ac he, perform the operation, and insert the result into c ac he. c omputing map hides c ac he management: register a c omputing Func tion, then just c all feedCac he.get
util.concurrent
Future basics ListenableFuture Futures more about Future Service Executor
Future basics
"A handle to an in-progress computation." "A promise from a service to supply us with a result."
different phrasings of the same thing
Future basics
Map<LocalDate, Long> pastSales = archiveService.readSales(); Map<LocalDate, Long> projectedSales = projectionService.projectSales(); return buildChart(pastSales, projectedSales);
we tell a network thread to make a request, and then we bloc k. the network thread sends the request to a server. the server responds to a network thread, and the network thread unbloc ks us repeat ~5s eac h; done in ~10s our thread is doing nothing; it handed off work to another thread/mac hine there's no reason not to overlap the two do-nothing periods, but this c ode c an't
Future basics
inparallel { Map<LocalDate, Long> pastSales = archiveService.readSales(); Map<LocalDate, Long> projectedSales = projectionService.projectSales(); } return buildChart(pastSales, projectedSales);
a possible solution is to modify the language to support an inparallel keyword instead of waiting for the sum of the two operations' durations, we now wait for the max
Future basics
Future<Map<LocalDate, Long>> pastSales = archiveService.readSales(); Future<Map<LocalDate, Long>> projectedSales = projectionService.projectSales(); return buildChart(pastSales.get(), projectedSales.get());
in Java, there's no inparallel, but we c an c hange our methods to return a Future this allows us to split the operation into "make request" and "wait for results" phases the method c alls now make queries but don't wait for their results; when we're done with all our other work, we c all get(), whic h does wait
util.concurrent: ListenableFuture
What Why When How
"aspec ts" in the sense of aspec t-oriented programming, c ode that runs automatic ally every time we do something without inserting that c ode into the main implementation traditional example is that you have an RPC interfac e and want to log every c all. you c ould reimplement the interfac e yourself suc h that every method does two things, log and delegate. or you c ould use guic e or some other interc eptor interfac e to implement one method to be automatic ally invoked whenever a c all is made here you're not the one who is using the output of the future (or at least you're not the primary c onsumer); someone else will c all get() on it later to ac c ess the result This c an work, but it's not the most popular use of ListenableFuture, either.
util.concurrent: Futures
transform chain allAsList / successfulAsList others that I won't cover here
I said I'd give some examples of methods operating on futures; here they are
Function<QueryResult, List<Row>> rowsFunction = new Function<QueryResult, List<Row>>() { public List<Row> apply(QueryResult queryResult) { return queryResult.getRows(); } }; Future<List<Row>> rowsFuture = transform(queryFuture, rowsFunction);
trivial postproc essing that won't fail: e.g., proto to java objec t the output value is the output of the Func tion, or an exc eption if the original future failed
util.concurrent: Executor
MoreExecutors.sameThreadExecutor for quick tasks that can run inline MoreExecutors.getExitingExecutorService for "half-daemon" threads UncaughtExceptionHandlers.systemExit for exiting after unexpected errors ThreadFactoryBuilder new ThreadFactoryBuilder() .setDaemon(true) .setNameFormat("WebRequestHandler-%d") .build();
plus others I won't c over here use sameThreadExec utor only when you literally don't c are whic h thread runs the task; think of it as "anyThreadExec utor" don't get c ute, e.g. "my future's value c omes from a task in thread pool X, so if I use sameThreadExec utor, my listener will run in that thread pool." that's *usually* true, but if your addListener c all oc c urs *after* the future c ompletes, now your listener is running in the thread that invoked addListener instead don't let me sc are you away from sameThreadExec utor entirely, but reserve it for fast tasks only "half-daemon" solves the following problem with important bac kground tasks: if your threads are non-daemon, the proc ess c an't exit automatic ally; if they're daemon, the proc ess will exit without waiting for them to finish getExitingExec utorServic e threads keep the VM alive only as long as they are doing something one c onfiguration option you have when setting up a thread pool is what to do with unhandled exc eptions. by default, they're printed to stderr (not your logs), and the thread (not the proc ess) dies, whic h might be bad if thread is important; maybe you don't know what it was in the middle of another option in setting up thread pool is to set other properties of individual threads; to help, we provide ThreadFac toryBuilder
util.concurrent: Service
definition lifecycle implementation
dispatcher.listenForConnections(port, queue);
new Thread("stop webserver") { public void run() { try { webserver.blockingShutdown(); notifyStopped(); } catch (Exception e) { notifyFailed(e); } } }.start();
for servic es that require full, manual thread management here, we need manual thread management bec ause our webserver doesn't have an async hronous stopAndNotifyCallbac k method. stop() isn't allow to bloc k, so our doStop() kic ks off its own thread if not for that, we c ould use Abstrac tExec utionThreadServic e, with the c ontents of doStart() moved to run() the lac k of an async hronous shutdown method is exac tly the kind of annoyanc e that Servic e exists to paper over
Questions?
Bugs Usage (use the tag guava) Discussion