Home arrow Java & J2EE arrow Page 4 - Taming Tiger: Concurrent Collections

Using the ConcurrentMap implementation - Java

Moving beyond Map, Collection, List, and Set: John Zukowski discusses the new library release in the Tiger release of the J2SE platform and what it provides: a set of utilities commonly needed in concurrent programs. If you are interested in optimizing multithreaded access to your collections, you've come to the right place. (This intermediate-level article was first published by IBM developerWorks, June 16, 2004, at http://www.ibm.com/developerWorks.)

TABLE OF CONTENTS:
  1. Taming Tiger: Concurrent Collections
  2. Using the Basic Queues
  3. Using the Blocking Queues
  4. Using the ConcurrentMap implementation
  5. Resources
By: developerWorks
Rating: starstarstarstarstar / 11
October 27, 2004

print this article
SEARCH DEV SHED

TOOLS YOU CAN USE

advertisement

The new java.util.concurrent.ConcurrentMap interface and the ConcurrentHashMap implementation let you add an element to a map only if the key isn't present and remove an element from a map only if the key is present and mapped to a specific value.

For adding to the map, there's the new putIfAbsent() method. The method accepts the key and value to add to the ConcurrentMap implementation, like the normal put() method, but will only add the key to the map if the map doesn't contain the key. If the map already contains the key, the existing value for the key is preserved. The putIfAbsent() method is atomic. Without calling this atomic operation, the code in Listing 4 would need to be called from an appropriately synchronized block:

Listing 4. Equivalent putIfAbsent() code


  if (!map.containsKey(key)) {
    return map.put(key, value);
  } else {
    return map.get(key);
  }


Like the putIfAbsent() method, the overloaded version of the remove() method accepts two arguments -- a key and value. When called, it will only remove the key from the map if the key is mapped to the specific value. If there is no match, the key isn't removed, and false is returned. If the value matches the current map contents for the key, the key is removed. Listing 5 shows the equivalent source for this operation:

Listing 5. Equivalent remove() code

  if (map.get(key).equals(value)) {
    map.remove(key);
    return true;
  } else {
    return false;
  }

Using CopyOnWriteArrayList and CopyOnWriteArraySet

The copy-on-write pattern is described best in Doug Lea's Concurrent Programming in Java book, Chapter 2, Section 2.4.4 (see Resources list). Essentially, the pattern states that to maintain a consistent snapshot of an object, you rely on immutability to eliminate the need for synchronization when you need to coordinate readings of separate but related attributes. For collections, that means that if you have a lot of reads (that is, get()) and iterations, you don't have to synchronize the operations to worry about the occasional write (that is, add()) call. For the new CopyOnWriteArrayList and CopyOnWriteArraySet classes, all mutable operations make a copy of the backing array first, make the change to the copy, and then replace the copy. This behavior guarantees that ConcurrentModificationException will never be thrown while iterating over a collection that is changing underneath itself. Iterating through the collection will complete with the original collection, while the updated collection will be available for future operations.

These new collections, CopyOnWriteArrayList and CopyOnWriteArraySet, work best when the read operations typically far outweigh the write operations. One example frequently mentioned is for the use of listener lists. Having said that, the Swing components have not been modified to use the new collections. Instead, they continue to use a javax.swing.event.EventListenerList for the maintenance of their lists of listeners.

As Listing 6 demonstrates, the use of the collection is identical to their non-copy-on-write alternative. Just create the collection and add or remove elements from it. Even as objects get added to the collection, the original Iterator can proceed, working through the items in the original collection.

Listing 6. Demonstrating a copy-on-write collection

import java.util.*;
import java.util.concurrent.*;

public class CopyOnWrite {
  public static void main(String args[]) {
    List list1 = new CopyOnWriteArrayList(Arrays.asList(args));
    List list2 = new ArrayList(Arrays.asList(args));
    Iterator itor1 = list1.iterator();
    Iterator itor2 = list2.iterator();
    list1.add("New");
    list2.add("New");
    try {
      printAll(itor1);
    } catch (ConcurrentModificationException e) {
      System.err.println("Shouldn't get here");
    }
    try {
      printAll(itor2);
    } catch (ConcurrentModificationException e) {
      System.err.println("Will get here.");
    }
  }
  private static void printAll(Iterator itor) {
    while (itor.hasNext()) {
      System.out.println(itor.next());
    }
  }
}

The sample program creates both a CopyOnWriteArrayList and ArrayList instance from the command line arguments. After getting an Iterator from each, an element is added to each. The CopyOnWriteArrayList iteration is able to proceed without exception while the ArrayList iteration stops immediately with a ConcurrentModificationException problem, because the original collection changed after getting the iterator. As long as this is the behavior you want, like for notifying all of the elements in the original set of event listeners, you're better off using the copy-on-write collections. If not, stick with the originals, and be sure to deal with the exception if and when it happens.

Conclusion

There are many big additions to the Tiger release of the J2SE platform. In addition to the language-level changes like generics support, this one library is probably the biggest addition as far as what will be used by the widest audiences. Not to belittle other packages added to the platform, like the Java Management Extensions (JMX), but most other big library enhancements are meant for narrower groups of developers. This library isn't. In addition to the other concurrency utilities for locking and atomic operations, expect to use these classes regularly. Learn them early and take advantage of what they offer.

IBM developerWorksVisit developerWorks for thousands of developer articles, tutorials, and resources related to open standard technologies, IBM products, and more. See developerWorks.



 
 
>>> More Java & J2EE Articles          >>> More By developerWorks
 

blog comments powered by Disqus
escort Bursa Bursa escort Antalya eskort
   

JAVA & J2EE ARTICLES

- More Java Bugs Lead to More Attacks
- Oracle's Java One Brings News, Surprises
- Oracle Patches Java Runtime Environment
- Apple Syncs Java Update with Oracle
- Spring 3.1 Java Development Framework Compat...
- Jelastic Java PaaS Availability and Pricing ...
- NetBeans 7.1 Released, Supports JavaFX 2
- SolarWinds Releases Newest Version of Java M...
- Free Monitoring Tool for Java Apps on Heroku
- Heroku Adds JCloud Platform Support, Java 7 ...
- Java SE 8 Speculation in Full Swing
- Java SE 7 Now Available
- New JVM Language and Java Reporting Tool
- Java 7 Release Update and New Eclipse Toolkit
- The Best Java Netbeans IDE Plugins

Developer Shed Affiliates

 


Dev Shed Tutorial Topics: