Sei sulla pagina 1di 24

7/10/13

Sponsored by:

http://www.javaworld.com/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html

This story appeared on JavaWorld at http://www.javaworld.com/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html

Java 101: The next generation: Java concurrency without the pain, Part 1
Get started with the Java Concurrency Utilities
By Jeff Friesen, JavaWorld.com, 06/19/13 With the increasingly complexity of concurrent applications, many developers find that Java's low-level threading capabilities are insufficient to their programming needs. In that case, it might be time to discover the Java Concurrency Utilities. Get started with j a v a . u t i l . c o n c u r r e n t , with Jeff Friesen's detailed introduction to the Executor framework, synchronizer types, and the Java Concurrent Collections package. Java 101: The next generation The first article in this new JavaWorld series introduces the Java Date and Time API. The Java platform provides low-level threading capabilities that enable developers to write concurrent applications where different threads execute simultaneously. Standard Java threading has some downsides, however: Java's low-level concurrency primitives (s y n c h r o n i z e d ,v o l a t i l e ,w a i t ( ) ,n o t i f y ( ) , and n o t i f y A l l ( ) ) aren't easy to use correctly. Threading hazards like deadlock, thread starvation, and race conditions, which result from incorrect use of primitives, are also hard to detect and debug. Relying on s y n c h r o n i z e dto coordinate access between threads leads to performance issues that affect application scalability, a requirement for many modern applications. Java's basic threading capabilities are too low level. Developers often need higher level constructs like semaphores and thread pools, which Java's low-level threading capabilities don't offer. As a result, developers will build their own constructs, which is both time consuming and error prone. The JSR 166: Concurrency Utilities framework was designed to meet the need for a high-level threading facility. Initiated in early 2002, the framework was formalized and implemented two years later in Java 5. Enhancements have followed in Java 6, Java 7, and the forthcoming Java 8. This two-part Java 101: The next generation series introduces software developers familiar with basic Java threading to the Java Concurrency Utilities packages and framework. In Part 1, I present an overview of the Java Concurrency
www.javaworld.com/cgi-bin/mailto/x_java.cgi?pagetosend=/export/home/httpd/javaworld/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html&pagen 1/24

7/10/13

http://www.javaworld.com/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html

Utilities framework and introduce its Executor framework, synchronizer utilities, and the Java Concurrent Collections package. Understanding Java threads Before you dive into this series, make sure you are familiar with the basics of threading. Start with the Java 101 introduction to Java's low-level threading capabilities: Part 1: Introducing threads and runnables Part 2: Thread synchronization Part 3: Thread scheduling, wait/notify, and thread interruption Part 4: Thread groups, volatility, thread-local variables, timers, and thread death

Inside the Java Concurrency Utilities


The Java Concurrency Utilities framework is a library of types that are designed to be used as building blocks for creating concurrent classes or applications. These types are thread-safe, have been thoroughly tested, and offer high performance. Types in the Java Concurrency Utilities are organized into small frameworks; namely, Executor framework, synchronizer, concurrent collections, locks, atomic variables, and Fork/Join. They are further organized into a main package and a pair of subpackages: java.util.concurrent contains high-level utility types that are commonly used in concurrent programming. Examples include semaphores, barriers, thread pools, and concurrent hashmaps. The java.util.concurrent.atomic subpackage contains low-level utility classes that support lock-free thread-safe programming on single variables. The java.util.concurrent.locks subpackage contains low-level utility types for locking and waiting for conditions, which are different from using Java's low-level synchronization and monitors. The Java Concurrency Utilities framework also exposes the low-level compare-and-swap (CAS) hardware instruction, variants of which are commonly supported by modern processors. CAS is much more lightweight than Java's monitorbased synchronization mechanism and is used to implement some highly scalable concurrent classes. The CAS-based j a v a . u t i l . c o n c u r r e n t . l o c k s . R e e n t r a n t L o c kclass, for instance, is more performant than the equivalent monitor-based s y n c h r o n i z e dprimitive. R e e n t r a n t L o c koffers more control over locking. (In Part 2 I'll explain more about how CAS works in j a v a . u t i l . c o n c u r r e n t .) System.nanoTime() The Java Concurrency Utilities framework includes l o n gn a n o T i m e ( ) , which is a member of the j a v a . l a n g . S y s t e m class. This method enables access to a nanosecond-granularity time source for making relative time measurements. In the next sections I'll introduce three useful features of the Java Concurrency Utilities, first explaining why they're so important to modern concurrency and then demonstrating how they work to increase the speed, reliability, efficiency, and scalability of concurrent Java applications.

The Executor framework


www.javaworld.com/cgi-bin/mailto/x_java.cgi?pagetosend=/export/home/httpd/javaworld/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html&pagen 2/24

7/10/13

http://www.javaworld.com/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html

In threading, a task is a unit of work. One problem with low-level threading in Java is that task submission is tightly coupled with a task-execution policy, as demonstrated by Listing 1. Listing 1. Server.java (Version 1)
i m p o r tj a v a . i o . I O E x c e p t i o n ; i m p o r tj a v a . n e t . S e r v e r S o c k e t ; i m p o r tj a v a . n e t . S o c k e t ; c l a s sS e r v e r { p u b l i cs t a t i cv o i dm a i n ( S t r i n g [ ]a r g s )t h r o w sI O E x c e p t i o n { S e r v e r S o c k e ts o c k e t=n e wS e r v e r S o c k e t ( 9 0 0 0 ) ; w h i l e( t r u e ) { f i n a lS o c k e ts=s o c k e t . a c c e p t ( ) ; R u n n a b l er=n e wR u n n a b l e ( ) { @ O v e r r i d e p u b l i cv o i dr u n ( ) { d o W o r k ( s ) ; } } ; n e wT h r e a d ( r ) . s t a r t ( ) ; } } s t a t i cv o i dd o W o r k ( S o c k e ts ) { } }

The above code describes a simple server application (with d o W o r k ( S o c k e t )left empty for brevity). The server thread repeatedly calls s o c k e t . a c c e p t ( )to wait for an incoming request, and then starts a thread to service this request when it arrives. Because this application creates a new thread for each request, it doesn't scale well when faced with a huge number of requests. For example, each created thread requires memory, and too many threads may exhaust the available memory, forcing the application to terminate. You could solve this problem by changing the task-execution policy. Rather than always creating a new thread, you could use a thread pool, in which a fixed number of threads would service incoming tasks. You would have to rewrite the application to make this change, however.
j a v a . u t i l . c o n c u r r e n tincludes the Executor framework,

a small framework of types that decouple task submission from task-execution policies. Using the Executor framework, it is possible to easily tune a program's task-execution policy without having to significantly rewrite your code.

Inside the Executor framework


The Executor framework is based on the E x e c u t o rinterface, which describes an executor as any object capable of executing j a v a . l a n g . R u n n a b l etasks. This interface declares the following solitary method for executing a R u n n a b l e
www.javaworld.com/cgi-bin/mailto/x_java.cgi?pagetosend=/export/home/httpd/javaworld/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html&pagen 3/24

7/10/13

http://www.javaworld.com/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html

task:
v o i de x e c u t e ( R u n n a b l ec o m m a n d )

You submit a R u n n a b l etask by passing it to e x e c u t e ( R u n n a b l e ) . If the executor cannot execute the task for any reason (for instance, if the executor has been shut down), this method will throw a R e j e c t e d E x e c u t i o n E x c e p t i o n . The key concept is that task submission is decoupled from the task-execution policy, which is described by an E x e c u t o rimplementation. The runnable task is thus able to execute via a new thread, a pooled thread, the calling thread, and so on. Note that E x e c u t o ris very limited. For example, you can't shut down an executor or determine whether an asynchronous task has finished. You also can't cancel a running task. For these and other reasons, the Executor framework provides an ExecutorService interface, which extends E x e c u t o r . Five of E x e c u t o r S e r v i c e 's methods are especially noteworthy: boolean awaitTermination(long timeout, TimeUnit unit) blocks the calling thread until all tasks have completed execution after a shutdown request, the timeout occurs, or the current thread is interrupted, whichever happens first. The maximum time to wait is specified by t i m e o u t , and this value is expressed in the u n i tunits specified by the T i m e U n i tenum; for example, T i m e U n i t . S E C O N D S . This method throws j a v a . l a n g . I n t e r r u p t e d E x c e p t i o nwhen the current thread is interrupted. It returns true when the executor is terminated and false when the timeout elapses before termination. boolean isShutdown() returns true when the executor has been shut down. void shutdown() initiates an orderly shutdown in which previously submitted tasks are executed but no new tasks are accepted. <T> Future<T> submit(Callable<T> task) submits a value-returning task for execution and returns a F u t u r e representing the pending results of the task. Future<?> submit(Runnable task) submits a R u n n a b l etask for execution and returns a F u t u r erepresenting that task. The F u t u r e < V >interface represents the result of an asynchronous computation. The result is known as a future because it typically will not be available until some moment in the future. You can invoke methods to cancel a task, return a task's result (waiting indefinitely or for a timeout to elapse when the task hasn't finished), and determine if a task has been cancelled or has finished. The C a l l a b l e < V >interface is similar to the R u n n a b l einterface in that it provides a single method describing a task to execute. Unlike R u n n a b l e 's v o i dr u n ( )method, C a l l a b l e < V > 's V c a l l ( )t h r o w sE x c e p t i o nmethod can return a value and throw an exception.

Executor factory methods


At some point, you'll want to obtain an executor. The Executor framework supplies the E x e c u t o r sutility class for this purpose. E x e c u t o r soffers several factory methods for obtaining different kinds of executors that offer specific threadexecution policies. Here are three examples: ExecutorService newCachedThreadPool() creates a thread pool that creates new threads as needed, but which reuses previously constructed threads when they're available. Threads that haven't been used for 60 seconds are terminated and removed from the cache. This thread pool typically improves the performance of programs that execute many short-lived asynchronous tasks.
www.javaworld.com/cgi-bin/mailto/x_java.cgi?pagetosend=/export/home/httpd/javaworld/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html&pagen 4/24

7/10/13

http://www.javaworld.com/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html

ExecutorService newSingleThreadExecutor() creates an executor that uses a single worker thread operating off an unbounded queue -- tasks are added to the queue and execute sequentially (no more than one task is active at any one time). If this thread terminates through failure during execution before shutdown of the executor, a new thread will be created to take its place when subsequent tasks need to be executed. ExecutorService newFixedThreadPool(int nThreads) creates a thread pool that re-uses a fixed number of execute JS At hide console show source threads operating off a shared unbounded queue. most n T h r e a d s threads are actively processing tasks. If additional tasks are submitted when all threads are active, they wait in the queue until a thread is available. If any thread terminates through failure during execution before shutdown, a new thread will be created to take its place when subsequent tasks need to be executed. The pool's threads exist until the executor is shut down. The Executor framework offers additional types (such as the S c h e d u l e d E x e c u t o r S e r v i c einterface), but the types you are likely to work with most often are E x e c u t o r S e r v i c e ,F u t u r e ,C a l l a b l e , and E x e c u t o r s . See the j a v a . u t i l . c o n c u r r e n tJavadoc to explore additional types.

Working with the Executor framework


You'll find that the Executor framework is fairly easy to work with. In Listing 2, I've used E x e c u t o rand E x e c u t o r sto replace the server example from Listing 1 with a more scalable thread pool-based alternative. Listing 2. Server.java (Version 2)
i m p o r tj a v a . i o . I O E x c e p t i o n ; i m p o r tj a v a . n e t . S e r v e r S o c k e t ; i m p o r tj a v a . n e t . S o c k e t ; i m p o r tj a v a . u t i l . c o n c u r r e n t . E x e c u t o r ; i m p o r tj a v a . u t i l . c o n c u r r e n t . E x e c u t o r s ; c l a s sS e r v e r { s t a t i cE x e c u t o rp o o l=E x e c u t o r s . n e w F i x e d T h r e a d P o o l ( 5 ) ; p u b l i cs t a t i cv o i dm a i n ( S t r i n g [ ]a r g s )t h r o w sI O E x c e p t i o n { S e r v e r S o c k e ts o c k e t=n e wS e r v e r S o c k e t ( 9 0 0 0 ) ; w h i l e( t r u e ) { f i n a lS o c k e ts=s o c k e t . a c c e p t ( ) ; R u n n a b l er=n e wR u n n a b l e ( ) { @ O v e r r i d e p u b l i cv o i dr u n ( ) { d o W o r k ( s ) ; } } ; p o o l . e x e c u t e ( r ) ; } } s t a t i cv o i dd o W o r k ( S o c k e ts ) { }
www.javaworld.com/cgi-bin/mailto/x_java.cgi?pagetosend=/export/home/httpd/javaworld/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html&pagen 5/24

7/10/13

http://www.javaworld.com/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html

Listing 2 uses n e w F i x e d T h r e a d P o o l ( i n t )to obtain a thread pool-based executor that reuses five threads. It also replaces n e wT h r e a d ( r ) . s t a r t ( ) ;with p o o l . e x e c u t e ( r ) ;for executing runnable tasks via any of these threads. Listing 3 presents another example in which an application reads the contents of an arbitrary web page. It outputs the resulting lines or an error message if the contents aren't available within a maximum of five seconds. Listing 3. ReadWebPage.java
i m p o r tj a v a . i o . B u f f e r e d R e a d e r ; i m p o r tj a v a . i o . I n p u t S t r e a m R e a d e r ; i m p o r tj a v a . i o . I O E x c e p t i o n ; i m p o r tj a v a . n e t . H t t p U R L C o n n e c t i o n ; i m p o r tj a v a . n e t . M a l f o r m e d U R L E x c e p t i o n ; i m p o r tj a v a . n e t . U R L ; i m p o r tj a v a . u t i l . A r r a y L i s t ; i m p o r tj a v a . u t i l . L i s t ; i m p o r tj a v a . u t i l . c o n c u r r e n t . C a l l a b l e ; i m p o r tj a v a . u t i l . c o n c u r r e n t . E x e c u t i o n E x c e p t i o n ; i m p o r tj a v a . u t i l . c o n c u r r e n t . E x e c u t o r s ; i m p o r tj a v a . u t i l . c o n c u r r e n t . E x e c u t o r S e r v i c e ; i m p o r tj a v a . u t i l . c o n c u r r e n t . F u t u r e ; i m p o r tj a v a . u t i l . c o n c u r r e n t . T i m e o u t E x c e p t i o n ; i m p o r tj a v a . u t i l . c o n c u r r e n t . T i m e U n i t ; p u b l i cc l a s sR e a d W e b P a g e { p u b l i cs t a t i cv o i dm a i n ( f i n a lS t r i n g [ ]a r g s ) { i f( a r g s . l e n g t h! =1 ) { S y s t e m . e r r . p r i n t l n ( " u s a g e :j a v aR e a d W e b P a g eu r l " ) ; r e t u r n ; } E x e c u t o r S e r v i c ee x e c u t o r=E x e c u t o r s . n e w S i n g l e T h r e a d E x e c u t o r ( ) ; C a l l a b l e < L i s t < S t r i n g > >c a l l a b l e ; c a l l a b l e=n e wC a l l a b l e < L i s t < S t r i n g > > ( ) { @ O v e r r i d e p u b l i cL i s t < S t r i n g >c a l l ( ) t h r o w sI O E x c e p t i o n ,M a l f o r m e d U R L E x c e p t i o n { L i s t < S t r i n g >l i n e s=n e wA r r a y L i s t < > ( ) ; U R Lu r l=n e wU R L ( a r g s [ 0 ] ) ; H t t p U R L C o n n e c t i o nc o n ; c o n=( H t t p U R L C o n n e c t i o n )u r l . o p e n C o n n e c t i o n ( ) ; I n p u t S t r e a m R e a d e ri s r ; i s r=n e wI n p u t S t r e a m R e a d e r ( c o n . g e t I n p u t S t r e a m ( ) ) ; B u f f e r e d R e a d e rb r ; b r=n e wB u f f e r e d R e a d e r ( i s r ) ; S t r i n gl i n e ; w h i l e( ( l i n e=b r . r e a d L i n e ( ) )! =n u l l ) l i n e s . a d d ( l i n e ) ; r e t u r nl i n e s ;
www.javaworld.com/cgi-bin/mailto/x_java.cgi?pagetosend=/export/home/httpd/javaworld/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html&pagen 6/24

7/10/13

http://www.javaworld.com/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html

} } ; F u t u r e < L i s t < S t r i n g > >f u t u r e=e x e c u t o r . s u b m i t ( c a l l a b l e ) ; t r y { L i s t < S t r i n g >l i n e s=f u t u r e . g e t ( 5 ,T i m e U n i t . S E C O N D S ) ; f o r( S t r i n gl i n e :l i n e s ) S y s t e m . o u t . p r i n t l n ( l i n e ) ; } c a t c h( E x e c u t i o n E x c e p t i o ne e ) { S y s t e m . e r r . p r i n t l n ( " C a l l a b l et h r o u g he x c e p t i o n :" + e e . g e t M e s s a g e ( ) ) ; } c a t c h( I n t e r r u p t e d E x c e p t i o n|T i m e o u t E x c e p t i o ne i t e ) { S y s t e m . e r r . p r i n t l n ( " U R Ln o tr e s p o n d i n g " ) ; } e x e c u t o r . s h u t d o w n ( ) ; } }

Listing 3's m a i n ( )method first verifies that a single (URL-based) command-line argument has been specified. It then creates a single-thread executor and a callable that tries to open a connection to this URL, read its contents line by line, and save these lines in a list, which it returns. The callable is subsequently submitted to the executor and a future representing the list of strings is returned. m a i n ( ) invokes the future's V g e t ( l o n gt i m e o u t ,T i m e U n i tu n i t )method to obtain this list.
g e t ( )throws T i m e o u t E x c e p t i o nwhen the callable doesn't finish within five seconds.

It throws E x e c u t i o n E x c e p t i o nwhen the callable throws an exception (for instance, the callable will throw j a v a . n e t . M a l f o r m e d U R L E x c e p t i o nwhen the URL is invalid). Regardless of whether an exception is thrown or not, the executor must be shut down before the application exits. If the executor isn't shut down, the application won't exit because the non-daemon thread-pool threads are still executing.

Synchronizers
Synchronizers are high-level constructs that coordinate and control thread execution. The Java Concurrency Utilities framework provides classes that implement semaphore, cyclic barrier, countdown latch, exchanger, and phaser synchronizers. I'll introduce each of these synchronizer types and then show you how they'd work in a concurrent Java application.

Semaphores
A semaphore is a thread-synchronization construct for controlling thread access to a common resource. It's often implemented as a protected variable whose value is incremented by an acquire operation and decremented by a release operation. The acquire operation either returns control to the invoking thread immediately or causes that thread to block when the semaphore's current value reaches a certain limit. The release operation decreases the current value, which causes a blocked thread to resume. Semaphores whose current values can be incremented past 1 are known as counting semaphores, whereas semaphores
www.javaworld.com/cgi-bin/mailto/x_java.cgi?pagetosend=/export/home/httpd/javaworld/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html&pagen 7/24

7/10/13

http://www.javaworld.com/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html

whose current values can be only 0 or 1 are known as binary semaphores or mutexes. In either case, the current value cannot be negative. The j a v a . l a n g . c o n c u r r e n t . S e m a p h o r eclass conceptualizes a semaphore as an object maintaining a set of permits. This class provides S e m a p h o r e ( i n tp e r m i t s )and S e m a p h o r e ( i n tp e r m i t s ,b o o l e a nf a i r ) constructors for specifying the number of permits. Each call to the S e m a p h o r e 's v o i da c q u i r e ( )method takes one of the available permits or blocks the calling thread when one isn't available. Each call to S e m a p h o r e 's v o i dr e l e a s e ( )method returns an available permit, potentially releasing a blocking acquirer thread.

Working with semaphores


Semaphores are often used to restrict the number of threads that can access a resource. Listing 4 demonstrates this capability by using a semaphore to control access to a pool of string items -- the source code is based on S e m a p h o r e 's Javadoc example code. Listing 4. SemaphoreDemo.java
i m p o r tj a v a . u t i l . c o n c u r r e n t . E x e c u t o r s ; i m p o r tj a v a . u t i l . c o n c u r r e n t . E x e c u t o r S e r v i c e ; i m p o r tj a v a . u t i l . c o n c u r r e n t . S e m a p h o r e ; p u b l i cc l a s sS e m a p h o r e D e m o { p u b l i cs t a t i cv o i dm a i n ( S t r i n g [ ]a r g s ) { f i n a lP o o lp o o l=n e wP o o l ( ) ; R u n n a b l er=n e wR u n n a b l e ( ) { @ O v e r r i d e p u b l i cv o i dr u n ( ) { S t r i n gn a m e=T h r e a d . c u r r e n t T h r e a d ( ) . g e t N a m e ( ) ; t r y { w h i l e( t r u e ) { S t r i n gi t e m ; S y s t e m . o u t . p r i n t f ( " % sa c q u i r i n g% s % n " ,n a m e , i t e m=p o o l . g e t I t e m ( ) ) ; T h r e a d . s l e e p ( 2 0 0 + ( i n t ) ( M a t h . r a n d o m ( ) * 1 0 0 ) ) ; S y s t e m . o u t . p r i n t f ( " % sp u t t i n gb a c k% s % n " , n a m e , i t e m ) ; p o o l . p u t I t e m ( i t e m ) ; } } c a t c h( I n t e r r u p t e d E x c e p t i o ni e ) { S y s t e m . o u t . p r i n t f ( " % si n t e r r u p t e d % n " ,n a m e ) ; } } } ; E x e c u t o r S e r v i c e [ ]e x e c u t o r s=n e w E x e c u t o r S e r v i c e [ P o o l . M A X _ A V A I L A B L E + 1 ] ;
www.javaworld.com/cgi-bin/mailto/x_java.cgi?pagetosend=/export/home/httpd/javaworld/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html&pagen 8/24

7/10/13

http://www.javaworld.com/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html

f o r( i n ti=0 ;i<e x e c u t o r s . l e n g t h ;i + + ) { e x e c u t o r s [ i ]=E x e c u t o r s . n e w S i n g l e T h r e a d E x e c u t o r ( ) ; e x e c u t o r s [ i ] . e x e c u t e ( r ) ; } } } f i n a lc l a s sP o o l { p u b l i cs t a t i cf i n a li n tM A X _ A V A I L A B L E=1 0 ; p r i v a t eS e m a p h o r ea v a i l a b l e=n e wS e m a p h o r e ( M A X _ A V A I L A B L E ,t r u e ) ; p r i v a t eS t r i n g [ ]i t e m s ; p r i v a t eb o o l e a n [ ]u s e d=n e wb o o l e a n [ M A X _ A V A I L A B L E ] ; P o o l ( ) { i t e m s=n e wS t r i n g [ M A X _ A V A I L A B L E ] ; f o r( i n ti=0 ;i<i t e m s . l e n g t h ;i + + ) i t e m s [ i ]=" I T E M " + i ; } S t r i n gg e t I t e m ( )t h r o w sI n t e r r u p t e d E x c e p t i o n { a v a i l a b l e . a c q u i r e ( ) ; r e t u r ng e t N e x t A v a i l a b l e I t e m ( ) ; } v o i dp u t I t e m ( S t r i n gi t e m ) { i f( m a r k A s U n u s e d ( i t e m ) ) a v a i l a b l e . r e l e a s e ( ) ; } p r i v a t es y n c h r o n i z e dS t r i n gg e t N e x t A v a i l a b l e I t e m ( ) { f o r( i n ti=0 ;i<M A X _ A V A I L A B L E ;+ + i ) { i f( ! u s e d [ i ] ) { u s e d [ i ]=t r u e ; r e t u r ni t e m s [ i ] ; } } r e t u r nn u l l ;/ /n o tr e a c h e d } p r i v a t es y n c h r o n i z e db o o l e a nm a r k A s U n u s e d ( S t r i n gi t e m ) { f o r( i n ti=0 ;i<M A X _ A V A I L A B L E ;+ + i ) { i f( i t e m= =i t e m s [ i ] ) { i f( u s e d [ i ] ) { u s e d [ i ]=f a l s e ; r e t u r nt r u e ; } e l s e
www.javaworld.com/cgi-bin/mailto/x_java.cgi?pagetosend=/export/home/httpd/javaworld/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html&pagen 9/24

7/10/13

http://www.javaworld.com/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html

r e t u r nf a l s e ; } } r e t u r nf a l s e ; } }

Listing 4 presents S e m a p h o r e D e m oand P o o lclasses. S e m a p h o r e D e m odrives the application by creating executors and having them execute a runnable that repeatedly acquires string item resources from a pool (implemented by P o o l ) and then returns them.
P o o lprovides S t r i n gg e t I t e m ( )and v o i dp u t I t e m ( S t r i n gi t e m )methods for obtaining and

returning resources. Before obtaining an item in g e t I t e m ( ) , a thread must acquire a permit from the semaphore, guaranteeing that an item is available for use. When the thread has finished with the item, it calls p u t I t e m ( S t r i n g ) , which returns the item to the pool and then returns a permit to the semaphore, which lets another thread acquire that item. No synchronization lock is held when a c q u i r e ( )is called because that would prevent an item from being returned to the pool. However, S t r i n gg e t N e x t A v a i l a b l e I t e m ( )and b o o l e a nm a r k A s U n u s e d ( S t r i n gi t e m )are s y n c h r o n i z e dto maintain pool consistency. (The semaphore encapsulates the synchronization needed to restrict access to the pool separately from the synchronization needed to maintain pool consistency.) Compile Listing 4 (j a v a cS e m a p h o r e D e m o . j a v a ) and run this application (j a v aS e m a p h o r e D e m o ). A prefix of the output generated from one run is shown below:
p o o l 1 t h r e a d 1a c q u i r i n gI T E M 0 p o o l 9 t h r e a d 1a c q u i r i n gI T E M 9 p o o l 7 t h r e a d 1a c q u i r i n gI T E M 8 p o o l 5 t h r e a d 1a c q u i r i n gI T E M 7 p o o l 3 t h r e a d 1a c q u i r i n gI T E M 6 p o o l 1 0 t h r e a d 1a c q u i r i n gI T E M 5 p o o l 8 t h r e a d 1a c q u i r i n gI T E M 4 p o o l 6 t h r e a d 1a c q u i r i n gI T E M 3 p o o l 4 t h r e a d 1a c q u i r i n gI T E M 2 p o o l 2 t h r e a d 1a c q u i r i n gI T E M 1 p o o l 5 t h r e a d 1p u t t i n gb a c kI T E M 7 p o o l 1 1 t h r e a d 1a c q u i r i n gI T E M 7 p o o l 9 t h r e a d 1p u t t i n gb a c kI T E M 9 p o o l 5 t h r e a d 1a c q u i r i n gI T E M 9 p o o l 7 t h r e a d 1p u t t i n gb a c kI T E M 8 p o o l 9 t h r e a d 1a c q u i r i n gI T E M 8 p o o l 3 t h r e a d 1p u t t i n gb a c kI T E M 6 p o o l 7 t h r e a d 1a c q u i r i n gI T E M 6

In the above output, eleven threads compete for ten resources. Thread p o o l 1 1 t h r e a d 1is forced to wait when it attempts to acquire a resource. It resumes with the I T E M 7resource when thread p o o l 5 t h r e a d 1returns this resource to the pool.

Cyclic barriers
A cyclic barrier is a thread-synchronization construct that lets a set of threads wait for each other to reach a common barrier point. The barrier is called cyclic because it can be re-used after the waiting threads are released. A cyclic barrier is implemented by the j a v a . l a n g . c o n c u r r e n t . C y c l i c B a r r i e rclass. This class provides the following constructors:
www.javaworld.com/cgi-bin/mailto/x_java.cgi?pagetosend=/export/home/httpd/javaworld/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html&page 10/24

7/10/13

http://www.javaworld.com/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html

C y c l i c B a r r i e r ( i n tn t h r e a d s ,R u n n a b l eb a r r i e r A c t i o n )causes a maximum of n t h r e a d s -1

threads to wait at the barrier. When one more thread arrives, it executes the nonnull b a r r i e r A c t i o nand then all threads proceed. This action is useful for updating shared state before any of the threads continue. C y c l i c B a r r i e r ( i n tn t h r e a d s )is similar to the previous constructor except that no runnable is executed when the barrier is tripped. Either constructor throws j a v a . l a n g . I l l e g a l A r g u m e n t E x c e p t i o nwhen the value passed to n t h r e a d sis less than 1.
C y c l i c B a r r i e rdeclares an i n ta w a i t ( )method

that typically causes the calling thread to wait unless the thread is the final thread. If so, and if a nonnull R u n n a b l ewas passed to b a r r i e r A c t i o n , the final thread executes the runnable before the other threads continue.
a w a i t ( )throws I n t e r r u p t e d E x c e p t i o nwhen the thread

that invoked this method is interrupted while waiting. This method throws B r o k e n B a r r i e r E x c e p t i o nwhen another thread was interrupted while the invoking thread was waiting, the barrier was broken when a w a i t ( )was called, or the barrier action (when present) failed because an exception was thrown from the runnable's r u n ( )method.

Working with cyclic barriers


Cyclic barriers can be used to perform lengthy calculations by breaking them into smaller individual tasks (as demonstrated by C y c l i c B a r r i e r 's Javadoc example code). They're also used in multiplayer games that cannot start until the last player has joined, as shown in Listing 5. Listing 5. CyclicBarrierDemo.java
i m p o r tj a v a . u t i l . c o n c u r r e n t . B r o k e n B a r r i e r E x c e p t i o n ; i m p o r tj a v a . u t i l . c o n c u r r e n t . C y c l i c B a r r i e r ; i m p o r tj a v a . u t i l . c o n c u r r e n t . E x e c u t o r s ; i m p o r tj a v a . u t i l . c o n c u r r e n t . E x e c u t o r S e r v i c e ; i m p o r tj a v a . u t i l . c o n c u r r e n t . T i m e U n i t ; p u b l i cc l a s sC y c l i c B a r r i e r D e m o { p u b l i cs t a t i cv o i dm a i n ( S t r i n g [ ]a r g s ) { R u n n a b l ea c t i o n=n e wR u n n a b l e ( ) { @ O v e r r i d e p u b l i cv o i dr u n ( ) { S t r i n gn a m e= T h r e a d . c u r r e n t T h r e a d ( ) . g e t N a m e ( ) ; S y s t e m . o u t . p r i n t f ( " T h r e a d% s" + " e x e c u t i n gb a r r i e r a c t i o n . % n " , n a m e ) ; } } ; f i n a lC y c l i c B a r r i e rb a r r i e r=n e wC y c l i c B a r r i e r ( 3 ,a c t i o n ) ; R u n n a b l et a s k=n e wR u n n a b l e ( ) { @ O v e r r i d e p u b l i cv o i dr u n ( )
www.javaworld.com/cgi-bin/mailto/x_java.cgi?pagetosend=/export/home/httpd/javaworld/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html&page 11/24

7/10/13

http://www.javaworld.com/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html

{ S t r i n gn a m e=T h r e a d . c u r r e n t T h r e a d ( ) . g e t N a m e ( ) ; S y s t e m . o u t . p r i n t f ( " % sa b o u tt oj o i ng a m e . . . % n " , n a m e ) ; t r y { b a r r i e r . a w a i t ( ) ; } c a t c h( B r o k e n B a r r i e r E x c e p t i o nb b e ) { S y s t e m . o u t . p r i n t l n ( " b a r r i e ri sb r o k e n " ) ; r e t u r n ; } c a t c h( I n t e r r u p t e d E x c e p t i o ni e ) { S y s t e m . o u t . p r i n t l n ( " t h r e a di n t e r r u p t e d " ) ; r e t u r n ; } S y s t e m . o u t . p r i n t f ( " % sh a sj o i n e dg a m e % n " ,n a m e ) ; } } ; E x e c u t o r S e r v i c e [ ]e x e c u t o r s=n e wE x e c u t o r S e r v i c e [ ] { E x e c u t o r s . n e w S i n g l e T h r e a d E x e c u t o r ( ) , E x e c u t o r s . n e w S i n g l e T h r e a d E x e c u t o r ( ) , E x e c u t o r s . n e w S i n g l e T h r e a d E x e c u t o r ( ) } ; f o r( E x e c u t o r S e r v i c ee x e c u t o r :e x e c u t o r s ) { e x e c u t o r . e x e c u t e ( t a s k ) ; e x e c u t o r . s h u t d o w n ( ) ; } } }

The above m a i n ( )method first creates a barrier action that's run by the last thread to reach the barrier. Next, a cyclic barrier is created. When three players arrive it trips and executes the barrier action. Reusing a CyclicBarrier To reuse a C y c l i c B a r r i e rinstance, invoke its v o i dr e s e t ( )method.
m a i n ( )now creates a runnable that outputs various status messages and

invokes a w a i t ( ) , followed by a threeexecutor array. Each executor runs this runnable and shuts down after the runnable finishes. Compile and run this application. You should see output similar to the following:
p o o l 1 t h r e a d 1a b o u tt oj o i ng a m e . . . p o o l 3 t h r e a d 1a b o u tt oj o i ng a m e . . . p o o l 2 t h r e a d 1a b o u tt oj o i ng a m e . . . T h r e a dp o o l 2 t h r e a d 1e x e c u t i n gb a r r i e ra c t i o n . p o o l 2 t h r e a d 1h a sj o i n e dg a m e p o o l 3 t h r e a d 1h a sj o i n e dg a m e p o o l 1 t h r e a d 1h a sj o i n e dg a m e

Countdown latches
www.javaworld.com/cgi-bin/mailto/x_java.cgi?pagetosend=/export/home/httpd/javaworld/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html&page 12/24

7/10/13

http://www.javaworld.com/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html

A countdown latch is a thread-synchronization construct that causes one or more threads to wait until a set of operations being performed by other threads finishes. It consists of a count and "cause a thread to wait until the count reaches zero" and "decrement the count" operations. The j a v a . u t i l . c o n c u r r e n t . C o u n t D o w n L a t c hclass implements a countdown latch. Its C o u n t D o w n L a t c h ( i n t c o u n t )constructor initializes the countdown latch to the specified c o u n t . A thread invokes the v o i da w a i t ( ) method to wait until the count has reached zero (or the thread has been interrupted). Subsequent calls to a w a i t ( )for a zero count return immediately. A thread calls v o i dc o u n t D o w n ( )to decrement the count.

Working with countdown latches


Countdown latches are useful for decomposing a problem into smaller pieces and giving a piece to a separate thread, as follows: 1. A main thread creates a countdown latch with a count of 1 that's used as a "starting gate" to start a group of worker threads simultaneously. 2. Each worker thread waits on the latch and the main thread decrements this latch to let all worker threads proceed. 3. The main thread waits on another countdown latch initialized to the number of worker threads. 4. When a worker thread completes, it decrements this count. After the count reaches zero (meaning that all worker threads have finished), the main thread proceeds and gathers the results. Listing 6 demonstrates this scenario. Listing 6. CountDownLatchDemo.java
i m p o r tj a v a . u t i l . c o n c u r r e n t . C o u n t D o w n L a t c h ; p u b l i cc l a s sC o u n t D o w n L a t c h D e m o { f i n a ls t a t i ci n tN=3 ; p u b l i cs t a t i cv o i dm a i n ( S t r i n g [ ]a r g s )t h r o w sI n t e r r u p t e d E x c e p t i o n { C o u n t D o w n L a t c hs t a r t S i g n a l=n e wC o u n t D o w n L a t c h ( 1 ) ; C o u n t D o w n L a t c hd o n e S i g n a l=n e wC o u n t D o w n L a t c h ( N ) ; f o r( i n ti=0 ;i<N ;+ + i )/ /c r e a t ea n ds t a r tt h r e a d s n e wT h r e a d ( n e wW o r k e r ( s t a r t S i g n a l ,d o n e S i g n a l ) ) . s t a r t ( ) ; S y s t e m . o u t . p r i n t l n ( " a b o u tt ol e tt h r e a d sp r o c e e d " ) ; s t a r t S i g n a l . c o u n t D o w n ( ) ;/ /l e ta l lt h r e a d sp r o c e e d S y s t e m . o u t . p r i n t l n ( " d o i n gw o r k " ) ; S y s t e m . o u t . p r i n t l n ( " w a i t i n gf o rt h r e a d st of i n i s h " ) ; d o n e S i g n a l . a w a i t ( ) ;/ /w a i tf o ra l lt h r e a d st of i n i s h S y s t e m . o u t . p r i n t l n ( " m a i nt h r e a dt e r m i n a t i n g " ) ; } } c l a s sW o r k e ri m p l e m e n t sR u n n a b l e { p r i v a t ef i n a ls t a t i ci n tN=5 ; p r i v a t ef i n a lC o u n t D o w n L a t c hs t a r t S i g n a l ; p r i v a t ef i n a lC o u n t D o w n L a t c hd o n e S i g n a l ;

www.javaworld.com/cgi-bin/mailto/x_java.cgi?pagetosend=/export/home/httpd/javaworld/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html&page

13/24

7/10/13

http://www.javaworld.com/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html

W o r k e r ( C o u n t D o w n L a t c hs t a r t S i g n a l ,C o u n t D o w n L a t c hd o n e S i g n a l ) { t h i s . s t a r t S i g n a l=s t a r t S i g n a l ; t h i s . d o n e S i g n a l=d o n e S i g n a l ; } @ O v e r r i d e p u b l i cv o i dr u n ( ) { t r y { S t r i n gn a m e=T h r e a d . c u r r e n t T h r e a d ( ) . g e t N a m e ( ) ; s t a r t S i g n a l . a w a i t ( ) ; f o r( i n ti=0 ;i<N ;i + + ) { S y s t e m . o u t . p r i n t f ( " t h r e a d% si sw o r k i n g % n " ,n a m e ) ; t r y { T h r e a d . s l e e p ( ( i n t ) ( M a t h . r a n d o m ( ) * 3 0 0 ) ) ; } c a t c h( I n t e r r u p t e d E x c e p t i o ni e ) { } } S y s t e m . o u t . p r i n t f ( " t h r e a d% sf i n i s h i n g % n " ,n a m e ) ; d o n e S i g n a l . c o u n t D o w n ( ) ; } c a t c h( I n t e r r u p t e d E x c e p t i o ni e ) { S y s t e m . o u t . p r i n t l n ( " i n t e r r u p t e d " ) ; } } }

Listing 6 presents C o u n t D o w n L a t c h D e m oand W o r k e rclasses. C o u n t D o w n L a t c h D e m o 's m a i n ( )method creates a s t a r t S i g n a lcountdown latch initialized to 1 and a d o n e S i g n a lcountdown latch initialized to 3, the number of worker threads.
m a i n ( )proceeds to

create three worker threads described by W o r k e rand then start these threads. After outputting a message, m a i n ( )executes s t a r t S i g n a l . c o u n t D o w n ( )to tell the worker threads that they can proceed. After outputting a few more messages, m a i n ( )executes d o n e S i g n a l . a w a i t ( )to wait until all worker threads have finished.
W o r k e r 's constructor saves these latches,

and its r u n ( )method performs some work. Before performing this work, the thread executes s t a r t S i g n a l . a w a i t ( )to block until the main thread allows it to proceed (by executing s t a r t S i g n a l . c o u n t D o w n ( ) ). The worker then enters a loop to simulate doing some work by alternately outputting messages and sleeping for random amounts of time. It then executes d o n e S i g n a l . c o u n t D o w n ( )to decrement the d o n e S i g n a lcountdown latch so that the main thread will eventually wake up. Compile and run this application. You should see output similar to the following:
a b o u tt ol e tt h r e a d sp r o c e e d d o i n gw o r k w a i t i n gf o rt h r e a d st of i n i s h
www.javaworld.com/cgi-bin/mailto/x_java.cgi?pagetosend=/export/home/httpd/javaworld/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html&page 14/24

7/10/13

http://www.javaworld.com/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html

t h r e a dT h r e a d 1i sw o r k i n g t h r e a dT h r e a d 0i sw o r k i n g t h r e a dT h r e a d 2i sw o r k i n g t h r e a dT h r e a d 1i sw o r k i n g t h r e a dT h r e a d 0i sw o r k i n g t h r e a dT h r e a d 0i sw o r k i n g t h r e a dT h r e a d 1i sw o r k i n g t h r e a dT h r e a d 2i sw o r k i n g t h r e a dT h r e a d 1i sw o r k i n g t h r e a dT h r e a d 2i sw o r k i n g t h r e a dT h r e a d 0i sw o r k i n g t h r e a dT h r e a d 0i sw o r k i n g t h r e a dT h r e a d 1i sw o r k i n g t h r e a dT h r e a d 2i sw o r k i n g t h r e a dT h r e a d 1f i n i s h i n g t h r e a dT h r e a d 0f i n i s h i n g t h r e a dT h r e a d 2i sw o r k i n g t h r e a dT h r e a d 2f i n i s h i n g m a i nt h r e a dt e r m i n a t i n g

Exchangers
An exchanger (also known as a rendezvous) is a thread-synchronization construct that lets a pair of threads exchange data items. An exchanger is similar to a cyclic barrier whose count is set to 2 but also supports exchange of data when both threads reach the barrier. The j a v a . u t i l . c o n c u r r e n t . E x c h a n g e r < V >class implements an exchanger. This class provides an E x c h a n g e r ( ) constructor for initializing an exchanger that describes an exchange point and a pair of e x c h a n g e ( )methods for performing an exchange. For example, V e x c h a n g e ( Vx )t h r o w sI n t e r r u p t e d E x c e p t i o nwaits for another thread to arrive at the exchange point (unless the current thread is interrupted) and then transfers the given object to it, receiving its object in return.

Working with exchangers


E x c h a n g e r 's Javadoc states that this synchronizer may be useful in genetic algorithms and

pipeline designs, where one thread fills a buffer and the other thread empties the buffer. When both threads meet at the exchange point, they swap their buffers. Listing 7 demonstrates. Listing 7. ExchangerDemo.java
i m p o r tj a v a . u t i l . A r r a y L i s t ; i m p o r tj a v a . u t i l . L i s t ; i m p o r tj a v a . u t i l . c o n c u r r e n t . E x c h a n g e r ; p u b l i cc l a s sE x c h a n g e r D e m o { s t a t i cE x c h a n g e r < D a t a B u f f e r >e x c h a n g e r=n e w E x c h a n g e r < D a t a B u f f e r > ( ) ; s t a t i cD a t a B u f f e ri n i t i a l E m p t y B u f f e r=n e wD a t a B u f f e r ( ) ; s t a t i cD a t a B u f f e ri n i t i a l F u l l B u f f e r=n e wD a t a B u f f e r ( " I T E M " ) ; p u b l i cs t a t i cv o i dm a i n ( S t r i n g [ ]a r g s )
www.javaworld.com/cgi-bin/mailto/x_java.cgi?pagetosend=/export/home/httpd/javaworld/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html&page 15/24

7/10/13

http://www.javaworld.com/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html

{ c l a s sF i l l i n g L o o pi m p l e m e n t sR u n n a b l e { i n tc o u n t=0 ; @ O v e r r i d e p u b l i cv o i dr u n ( ) { D a t a B u f f e rc u r r e n t B u f f e r=i n i t i a l E m p t y B u f f e r ; t r y { w h i l e( t r u e ) { a d d T o B u f f e r ( c u r r e n t B u f f e r ) ; i f( c u r r e n t B u f f e r . i s F u l l ( ) ) { S y s t e m . o u t . p r i n t l n ( " f i l l i n gl o o pt h r e a dw a n t st o e x c h a n g e " ) ; c u r r e n t B u f f e r=e x c h a n g e r . e x c h a n g e ( c u r r e n t B u f f e r ) ; S y s t e m . o u t . p r i n t l n ( " f i l l i n gl o o pt h r e a do b s e r v e sa n e x c h a n g e " ) ; } } } c a t c h( I n t e r r u p t e d E x c e p t i o ni e ) { S y s t e m . o u t . p r i n t l n ( " f i l l i n gl o o pt h r e a di n t e r r u p t e d " ) ; } } v o i da d d T o B u f f e r ( D a t a B u f f e rb u f f e r ) { S t r i n gi t e m=" N E W I T E M " + c o u n t + + ; S y s t e m . o u t . p r i n t f ( " A d d i n g% s % n " ,i t e m ) ; b u f f e r . a d d ( i t e m ) ; } } c l a s sE m p t y i n g L o o pi m p l e m e n t sR u n n a b l e { @ O v e r r i d e p u b l i cv o i dr u n ( ) { D a t a B u f f e rc u r r e n t B u f f e r=i n i t i a l F u l l B u f f e r ; t r y { w h i l e( t r u e ) { t a k e F r o m B u f f e r ( c u r r e n t B u f f e r ) ; i f( c u r r e n t B u f f e r . i s E m p t y ( ) ) { S y s t e m . o u t . p r i n t l n ( " e m p t y i n gl o o pt h r e a dw a n t st o e x c h a n g e " ) ; c u r r e n t B u f f e r=e x c h a n g e r . e x c h a n g e ( c u r r e n t B u f f e r ) ; S y s t e m . o u t . p r i n t l n ( " e m p t y i n gl o o pt h r e a do b s e r v e sa n e x c h a n g e " ) ; } } } c a t c h( I n t e r r u p t e d E x c e p t i o ni e )
www.javaworld.com/cgi-bin/mailto/x_java.cgi?pagetosend=/export/home/httpd/javaworld/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html&page 16/24

7/10/13

http://www.javaworld.com/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html

{ S y s t e m . o u t . p r i n t l n ( " e m p t y i n gl o o pt h r e a di n t e r r u p t e d " ) ; } } v o i dt a k e F r o m B u f f e r ( D a t a B u f f e rb u f f e r ) { S y s t e m . o u t . p r i n t f ( " t a k i n g% s % n " ,b u f f e r . r e m o v e ( ) ) ; } } n e wT h r e a d ( n e wE m p t y i n g L o o p ( ) ) . s t a r t ( ) ; n e wT h r e a d ( n e wF i l l i n g L o o p ( ) ) . s t a r t ( ) ; } } c l a s sD a t a B u f f e r { p r i v a t ef i n a ls t a t i ci n tM A X=1 0 ; p r i v a t eL i s t < S t r i n g >i t e m s=n e wA r r a y L i s t < > ( ) ; D a t a B u f f e r ( ) { } D a t a B u f f e r ( S t r i n gp r e f i x ) { f o r( i n ti=0 ;i<M A X ;i + + ) { S t r i n gi t e m=p r e f i x + i ; S y s t e m . o u t . p r i n t f ( " A d d i n g% s % n " ,i t e m ) ; i t e m s . a d d ( i t e m ) ; } } v o i da d d ( S t r i n gs ) { i f( ! i s F u l l ( ) ) i t e m s . a d d ( s ) ; } b o o l e a ni s E m p t y ( ) { r e t u r ni t e m s . s i z e ( )= =0 ; } b o o l e a ni s F u l l ( ) { r e t u r ni t e m s . s i z e ( )= =M A X ; } S t r i n gr e m o v e ( ) { i f( ! i s E m p t y ( ) ) r e t u r ni t e m s . r e m o v e ( 0 ) ; r e t u r nn u l l ; } }

Listing 7 is based on the example code in E x c h a n g e r 's Javadoc. One thread fills one buffer with strings while another
www.javaworld.com/cgi-bin/mailto/x_java.cgi?pagetosend=/export/home/httpd/javaworld/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html&page 17/24

7/10/13

http://www.javaworld.com/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html

thread empties another buffer. When the respective buffer is full or empty, these threads meet at an exchange point and swap buffers. For example, when the filling thread's c u r r e n t B u f f e r . i s F u l l ( )expression is true, it executes c u r r e n t B u f f e r= e x c h a n g e r . e x c h a n g e ( c u r r e n t B u f f e r )and waits. The emptying thread continues until c u r r e n t B u f f e r . i s E m p t y ( )evaluates to true, and also invokes e x c h a n g e ( c u r r e n t B u f f e r ) . At this point, the buffers are swapped and the threads continue. Compile and run this application. Your initial output should be similar to the following prefix:
A d d i n gI T E M 0 A d d i n gI T E M 1 A d d i n gI T E M 2 A d d i n gI T E M 3 A d d i n gI T E M 4 A d d i n gI T E M 5 A d d i n gI T E M 6 A d d i n gI T E M 7 A d d i n gI T E M 8 A d d i n gI T E M 9 t a k i n gI T E M 0 t a k i n gI T E M 1 t a k i n gI T E M 2 t a k i n gI T E M 3 t a k i n gI T E M 4 t a k i n gI T E M 5 t a k i n gI T E M 6 t a k i n gI T E M 7 t a k i n gI T E M 8 A d d i n gN E W I T E M 0 t a k i n gI T E M 9 A d d i n gN E W I T E M 1 e m p t y i n gl o o pt h r e a dw a n t st oe x c h a n g e A d d i n gN E W I T E M 2 A d d i n gN E W I T E M 3 A d d i n gN E W I T E M 4 A d d i n gN E W I T E M 5 A d d i n gN E W I T E M 6 A d d i n gN E W I T E M 7 A d d i n gN E W I T E M 8 A d d i n gN E W I T E M 9 f i l l i n gl o o pt h r e a dw a n t st oe x c h a n g e f i l l i n gl o o pt h r e a do b s e r v e sa ne x c h a n g e e m p t y i n gl o o pt h r e a do b s e r v e sa ne x c h a n g e A d d i n gN E W I T E M 1 0 A d d i n gN E W I T E M 1 1 t a k i n gN E W I T E M 0 t a k i n gN E W I T E M 1 A d d i n gN E W I T E M 1 2 t a k i n gN E W I T E M 2 t a k i n gN E W I T E M 3 A d d i n gN E W I T E M 1 3 t a k i n gN E W I T E M 4 t a k i n gN E W I T E M 5 A d d i n gN E W I T E M 1 4 t a k i n gN E W I T E M 6 t a k i n gN E W I T E M 7 A d d i n gN E W I T E M 1 5 t a k i n gN E W I T E M 8
www.javaworld.com/cgi-bin/mailto/x_java.cgi?pagetosend=/export/home/httpd/javaworld/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html&page 18/24

7/10/13

http://www.javaworld.com/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html

t a k i n gN E W I T E M 9 e m p t y i n gl o o pt h r e a dw a n t st oe x c h a n g e A d d i n gN E W I T E M 1 6 A d d i n gN E W I T E M 1 7 A d d i n gN E W I T E M 1 8 A d d i n gN E W I T E M 1 9 f i l l i n gl o o pt h r e a dw a n t st oe x c h a n g e f i l l i n gl o o pt h r e a do b s e r v e sa ne x c h a n g e e m p t y i n gl o o pt h r e a do b s e r v e sa ne x c h a n g e A d d i n gN E W I T E M 2 0

Phasers
A phaser is a thread-synchronization construct that's similar to a cyclic barrier in that it lets a group of threads wait on a barrier and then proceed after the last thread arrives. It also offers the equivalent of a barrier action. However, a phaser is more flexible. Unlike a cyclic barrier, which coordinates a fixed number of threads, a phaser can coordinate a variable number of threads, which can register at any time. To implement this capability, a phaser takes advantage of phases and phase numbers. A phase is the phaser's current state, and this state is identified by an integer-based phase number. When the last of the registered threads arrives at the phaser barrier, a phaser advances to the next phase and increments its phase number by 1. The j a v a . u t i l . c o n c u r r e n t . P h a s e rclass implements a phaser. Because this class is thoroughly described in its Javadoc, I'll point out only a few constructors and methods: The P h a s e r ( i n tt h r e a d s )constructor creates a phaser that initially coordinates n t h r e a d sthreads (which have yet to arrive at the phaser barrier) and whose phase number is initially set to 0. The i n tr e g i s t e r ( )method adds a new unarrived thread to this phaser and returns the phase number to which the arrival applies. This number is known as the arrival phase number. The i n ta r r i v e A n d A w a i t A d v a n c e ( )method records arrival and waits for the phaser to advance (which happens after the other threads have arrived). It returns the phase number to which the arrival applies. The i n ta r r i v e A n d D e r e g i s t e r ( )method arrives at this phaser and deregisters from it without waiting for others to arrive, reducing the number of threads required to advance in future phases.

Working with phasers


The small application in Listing 8 demonstrates the constructor and methods described above. Listing 8. PhaserDemo.java
i m p o r tj a v a . u t i l . A r r a y L i s t ; i m p o r tj a v a . u t i l . L i s t ; i m p o r tj a v a . u t i l . c o n c u r r e n t . P h a s e r ; p u b l i cc l a s sP h a s e r D e m o { p u b l i cs t a t i cv o i dm a i n ( S t r i n g [ ]a r g s ) { L i s t < R u n n a b l e >t a s k s=n e wA r r a y L i s t < > ( ) ;
www.javaworld.com/cgi-bin/mailto/x_java.cgi?pagetosend=/export/home/httpd/javaworld/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html&page 19/24

7/10/13

http://www.javaworld.com/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html

t a s k s . a d d ( n e wR u n n a b l e ( ) { @ O v e r r i d e p u b l i cv o i dr u n ( ) { S y s t e m . o u t . p r i n t f ( " % sr u n n i n ga t% d % n " , T h r e a d . c u r r e n t T h r e a d ( ) . g e t N a m e ( ) , S y s t e m . c u r r e n t T i m e M i l l i s ( ) ) ; } } ) ; t a s k s . a d d ( n e wR u n n a b l e ( ) { @ O v e r r i d e p u b l i cv o i dr u n ( ) { S y s t e m . o u t . p r i n t f ( " % sr u n n i n ga t% d % n " , T h r e a d . c u r r e n t T h r e a d ( ) . g e t N a m e ( ) , S y s t e m . c u r r e n t T i m e M i l l i s ( ) ) ; } } ) ; r u n T a s k s ( t a s k s ) ; } s t a t i cv o i dr u n T a s k s ( L i s t < R u n n a b l e >t a s k s ) { f i n a lP h a s e rp h a s e r=n e wP h a s e r ( 1 ) ;/ /" 1 "t or e g i s t e rs e l f / /c r e a t ea n ds t a r tt h r e a d s f o r( f i n a lR u n n a b l et a s k :t a s k s ) { p h a s e r . r e g i s t e r ( ) ; n e wT h r e a d ( ) { @ O v e r r i d e p u b l i cv o i dr u n ( ) { t r y { T h r e a d . s l e e p ( 5 0 + ( i n t ) ( M a t h . r a n d o m ( ) * 3 0 0 ) ) ; } c a t c h( I n t e r r u p t e d E x c e p t i o ni e ) { S y s t e m . o u t . p r i n t l n ( " i n t e r r u p t e dt h r e a d " ) ; } p h a s e r . a r r i v e A n d A w a i t A d v a n c e ( ) ;/ /a w a i ta l lc r e a t i o n t a s k . r u n ( ) ; } } . s t a r t ( ) ; } / /a l l o wt h r e a d st os t a r ta n dd e r e g i s t e rs e l f p h a s e r . a r r i v e A n d D e r e g i s t e r ( ) ; } }

Listing 8 is based on the first code example in P h a s e r 's Javadoc. This example shows how to use P h a s e rinstead of C o u n t D o w n L a t c hto control a one-shot action serving a variable number of threads. The application creates a pair of runnable tasks that each report the time (in milliseconds relative to the Unix epoch) at which its starts to run. Compile and run this application, and you should observe output that's similar to the following:
www.javaworld.com/cgi-bin/mailto/x_java.cgi?pagetosend=/export/home/httpd/javaworld/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html&page 20/24

7/10/13

http://www.javaworld.com/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html

T h r e a d 0r u n n i n ga t1 3 6 6 3 1 5 2 9 7 6 3 5 T h r e a d 1r u n n i n ga t1 3 6 6 3 1 5 2 9 7 6 3 5

As you would expect from countdown latch behavior, both threads start running at (in this case) the same time even though a thread may have been delayed by as much as 349 milliseconds thanks to the presence of T h r e a d . s l e e p ( ) . Comment out p h a s e r . a r r i v e A n d A w a i t A d v a n c e ( ) ;/ /a w a i ta l lc r e a t i o nand you should now observe the threads starting at radically different times, as illustrated below:
T h r e a d 1r u n n i n ga t1 3 6 6 3 1 5 4 2 8 8 7 1 T h r e a d 0r u n n i n ga t1 3 6 6 3 1 5 4 2 9 1 0 0

Concurrent collections
The Java Collections framework provides interfaces and classes in the j a v a . u t i lpackage that facilitate working with collections of objects. Interfaces include L i s t ,M a p , and S e t . Classes include A r r a y L i s t ,V e c t o r ,H a s h t a b l e , H a s h M a p , and T r e e S e t . Collections classes such as V e c t o rand H a s h t a b l eare thread-safe. You can make other classes (like A r r a y L i s t ) thread-safe by using synchronized wrapper factory methods such as C o l l e c t i o n s . s y n c h r o n i z e d M a p ( ) , C o l l e c t i o n s . s y n c h r o n i z e d L i s t ( ) , and C o l l e c t i o n s . s y n c h r o n i z e d S e t ( ) . There are a couple of problems with the thread-safe collections: 1. Code that iterates over a collection that might be modified by another thread during the iteration requires a lock to avoid a thrown j a v a . u t i l . C o n c u r r e n t M o d i f i c a t i o n E x c e p t i o n . This requirement is necessary because Collections framework classes return fail-fast iterators, which are iterators that throw C o n c u r r e n t M o d i f i c a t i o n E x c e p t i o nwhen a collection is modified during iteration. Fail-fast iterators are often an inconvenience to concurrent applications. 2. Performance often suffers when these synchronized collections are accessed frequently from multiple threads; this is a performance problem that impacts an application's scalability. The Java Concurrency Utilities framework overcomes these problems by introducing performant and highly-scalable collections-oriented types, which are part of j a v a . u t i l . c o n c u r r e n t . These collections-oriented classes return weakly consistent iterators, which have the following properties: When an element is removed after iteration starts, but hasn't yet been returned via the iterator's n e x t ( )method, it won't be returned. When an element is added after iteration starts, it may or may not be returned. Regardless of changes to the collection, no element is returned more than once in an iteration. The following list summarizes the Java Concurrency Utilities framework's collection-oriented types:
B l o c k i n g D e q u e < E > : This interface extends B l o c k i n g Q u e u eand j a v a . u t i l . D e q u eto

describe a doubleended queue with additional support for blocking operations that wait for the deque to become non-empty when retrieving an element, and wait for space to become available in the deque when storing an element. B l o c k i n g Q u e u e < E > : This interface extends j a v a . u t i l . Q u e u eto describe a queue with additional support for operations that wait for the queue to become non-empty when retrieving an element, and wait for space to become available in the queue when storing an element. C o n c u r r e n t M a p < K ,V > : This interface extends j a v a . u t i l . M a pto describe a map with additional atomic p u t I f A b s e n t ,r e m o v e , and r e p l a c emethods.
www.javaworld.com/cgi-bin/mailto/x_java.cgi?pagetosend=/export/home/httpd/javaworld/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html&page 21/24

7/10/13

http://www.javaworld.com/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html

C o n c u r r e n t N a v i g a b l e M a p < K ,V > : This interface extends C o n c u r r e n t M a pand j a v a . u t i l . N a v i g a b l e M a p

to describe a concurrent map with navigable operations. T r a n s f e r Q u e u e < E > : This interface extends B l o c k i n g Q u e u eto describe a blocking queue in which producers may wait for consumers to receive elements. A r r a y B l o c k i n g Q u e u e < E > : This class describes a bounded blocking queue backed by an array. C o n c u r r e n t H a s h M a p < K ,V > : This class describes a hash table supporting full concurrency of retrievals and adjustable expected concurrency for updates. C o n c u r r e n t L i n k e d D e q u e < E > : This class describes an unbounded thread-safe deque based on linked nodes. C o n c u r r e n t L i n k e d Q u e u e < E > : This class describes an unbounded thread-safe queue based on linked nodes. C o n c u r r e n t S k i p L i s t M a p < K ,V > : This class describes a scalable concurrent C o n c u r r e n t N a v i g a b l e M a p implementation. C o n c u r r e n t S k i p L i s t S e t < E > : This class describes a scalable concurrent j a v a . u t i l . N a v i g a b l e S e t implementation based on a C o n c u r r e n t S k i p L i s t M a p . C o p y O n W r i t e A r r a y L i s t < E > : This class describes a thread-safe variant of A r r a y L i s tin which all mutative operations (e.g., add and set) are implemented by making a fresh copy of the underlying array whenever an element is added or removed. However, in-progress iterations continue to work on the previous copy (when the iterator was created). Although there's some cost to copying the array, this cost is acceptable in situations where there are many more iterations than modifications. C o p y O n W r i t e A r r a y S e t < E > : This class describes a S e tthat uses an internal C o p y O n W r i t e A r r a y L i s tfor all of its operations. D e l a y Q u e u e < Ee x t e n d sD e l a y e d > : This class describes an unbounded blocking queue of j a v a . u t i l . c o n c u r r e n t . D e l a y e delements, in which an element can only be taken when its delay has expired. (D e l a y e dis an interface for marking objects that should be acted upon after a given delay.) L i n k e d B l o c k i n g D e q u e < E > : This class describes an optionally-bounded blocking deque based on linked nodes. L i n k e d B l o c k i n g Q u e u e < E > : This class describes an optionally-bounded blocking queue based on linked nodes. L i n k e d T r a n s f e r Q u e u e < E > : This class describes an unbounded transfer queue based on linked nodes. P r i o r i t y B l o c k i n g Q u e u e < E > : This class describes an unbounded blocking queue that uses the same ordering rules as j a v a . u t i l . P r i o r i t y Q u e u eand supplies blocking retrieval operations. S y n c h r o n o u s Q u e u e < E > : This class describes a blocking queue in which each insert operation must wait for a corresponding remove operation by another thread, and vice versa.

Working with Concurrent Collections


For an example of what you can do with Concurrent Collections, consider C o p y O n W r i t e A r r a y L i s t , as demonstrated in Listing 9. Listing 9. CopyOnWriteArrayListDemo.java
i m p o r tj a v a . u t i l . A r r a y L i s t ; i m p o r tj a v a . u t i l . C o n c u r r e n t M o d i f i c a t i o n E x c e p t i o n ; i m p o r tj a v a . u t i l . I t e r a t o r ; i m p o r tj a v a . u t i l . L i s t ; i m p o r tj a v a . u t i l . c o n c u r r e n t . C o p y O n W r i t e A r r a y L i s t ; p u b l i cc l a s sC o p y O n W r i t e A r r a y L i s t D e m o { p u b l i cs t a t i cv o i dm a i n ( S t r i n g [ ]a r g s ) { L i s t < S t r i n g >e m p L i s t=n e wA r r a y L i s t < > ( ) ; e m p L i s t . a d d ( " J o h nD o e " ) ;
www.javaworld.com/cgi-bin/mailto/x_java.cgi?pagetosend=/export/home/httpd/javaworld/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html&page 22/24

7/10/13

http://www.javaworld.com/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html

e m p L i s t . a d d ( " J a n eD o e " ) ; e m p L i s t . a d d ( " R i t aS m i t h " ) ; I t e r a t o r < S t r i n g >e m p I t e r=e m p L i s t . i t e r a t o r ( ) ; w h i l e( e m p I t e r . h a s N e x t ( ) ) t r y { S y s t e m . o u t . p r i n t l n ( e m p I t e r . n e x t ( ) ) ; i f( ! e m p L i s t . c o n t a i n s ( " T o mS m i t h " ) ) e m p L i s t . a d d ( " T o mS m i t h " ) ; } c a t c h( C o n c u r r e n t M o d i f i c a t i o n E x c e p t i o nc m e ) { S y s t e m . e r r . p r i n t l n ( " a t t e m p tt om o d i f yl i s td u r i n gi t e r a t i o n " ) ; b r e a k ; } L i s t < S t r i n g >e m p L i s t 2=n e wC o p y O n W r i t e A r r a y L i s t < > ( ) ; e m p L i s t 2 . a d d ( " J o h nD o e " ) ; e m p L i s t 2 . a d d ( " J a n eD o e " ) ; e m p L i s t 2 . a d d ( " R i t aS m i t h " ) ; e m p I t e r=e m p L i s t 2 . i t e r a t o r ( ) ; w h i l e( e m p I t e r . h a s N e x t ( ) ) { S y s t e m . o u t . p r i n t l n ( e m p I t e r . n e x t ( ) ) ; i f( ! e m p L i s t 2 . c o n t a i n s ( " T o mS m i t h " ) ) e m p L i s t 2 . a d d ( " T o mS m i t h " ) ; } } }

Listing 9 contrasts C o p y O n W r i t e A r r a y L i s t D e m owith A r r a y L i s tfrom a C o n c u r r e n t M o d i f i c a t i o n E x c e p t i o n perspective. During each iteration, an attempt is made to add a new employee name to the list. The A r r a y L i s titeration fails with this exception, whereas the C o p y O n W r i t e A r r a y L i s titeration ignores the addition. If you compile and run this application you should see the following output:
J o h nD o e a t t e m p tt om o d i f yl i s td u r i n gi t e r a t i o n J o h nD o e J a n eD o e R i t aS m i t h

In conclusion
The Java Concurrency Utilities framework offers a high-level alternative to Java's low-level threading capabilities. This library's thread-safe and high-performant types were designed to be used as the building blocks in concurrent classes and applications. The Java Concurrency Utilities framework is organized into several smaller frameworks, with types stored in j a v a . u t i l . c o n c u r r e n tand two subpackages, j a v a . u t i l . c o n c u r r e n t . a t o m i cand j a v a . u t i l . c o n c u r r e n t . l o c k s . In this article, I introduced three of these frameworks: the Executor framework, synchronizers, and the Java Concurrent Collections. You can learn more about them by exploring the exercises in this article's source code file. In Part 2 we'll explore locks, atomic variables, Fork/Join, and more.
www.javaworld.com/cgi-bin/mailto/x_java.cgi?pagetosend=/export/home/httpd/javaworld/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html&page 23/24

7/10/13

http://www.javaworld.com/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html

About the author


Jeff Friesen is a freelance tutor and software developer with an emphasis on Java and Android. In addition to writing Java and Android books for Apress, Jeff has written numerous articles on Java and other technologies for JavaWorld, informIT, Java.net, DevSource, and SitePoint. Jeff can be contacted via his website at TutorTutor.ca. Read more about Core Java in JavaWorld's Core Java section.
All contents copyright 1995-2013 Java World, Inc. http://www.javaworld.com

www.javaworld.com/cgi-bin/mailto/x_java.cgi?pagetosend=/export/home/httpd/javaworld/javaworld/jw-06-2013/130619-j101-java-concurrency-part-1.html&page

24/24

Potrebbero piacerti anche