Forum Controls
Spotlight Features

The Rich Engineering Heritage Behind Dependency Injection

Andrew McVeigh takes us on a tour of the rich heritage behind dependency injection, what it represents, and tells us why its here to stay.

NetBeans 6: Matisse Updates

NetBeans 6 delivers great updates to the Matisse GUI builder. Spend a few minutes with Roman Strobl and get an expert briefing on what's new and what has changed.

Introduction to Groovy Part 3

In this, the third and final installation of Andres' Introduction to Groovy series, you learn about how Groovy handles variable numbers of arguments, named parameters, currying, and more about Groovy operators. Including, some new operators.

Easier Custom Components with Swing Fuse

Swing Fuse (actually just Fuse), is a framework designed to make it easier to create your own custom desktop components. In this article, Daniel Spiewak shows you how to get started and provides sample source code you can download.

Benchmark Analysis: Guice vs Spring

Willam Louth shows how he uses JXInsight Probes to investigate probable performance issues with code bases that he is not familiar with. He also highlights possible pitfalls in creating a benchmark, as well as in the analysis of results.
Replies: 10 - Pages: 1  
Threads: [ Previous | Next ]
  Click to reply to this thread Reply

Read-Only Collections

At 7:44 AM on Mar 24, 2006, Jean-Marie Dautelle DeveloperZone Top 100 wrote:

Read-only collections are directly supported by the .NET platform (ReadOnlyCollectionBase). Unfortunately Java support for unmodifiable collections is limited with many pitfalls along the way.

This "tips & tricks" is more or less a summary of a current Javalobby discussion ( Mustang versus Tiger performance comparison ). Hopefully it will help Javalobby readers to avoid common pitfalls with read-only collections.

1. The Collections utility class.


Providing a read-only view of any collection/map/set/list in Java seems straightforward using the java.util.Collections utility class. For example:
    List<String> readOnlyList = Collections.unmodifiableList(myList);

The first thing you notice is that read-only collections are not differentiable from normal collections. In fact, there is nothing to indicate that a collection is read-only (there is no ReadOnlyList interface with read-only methods for example). The user has still access to the add/set/remove methods but calling these methods results in UnsupportedException being raised.

2. Read-Only view of mutable collections.


Let's say that you have a collection of existing "Units", and you want to provide users with a read-only view of these units. Unfortunately, the following code will fail miserably:
public class Unit {
     static ArrayList<Unit> INSTANCES = new ArrayList<unit>();
     public static List<Unit> getInstances() {
         return Collections.unmodifiableList(INSTANCES);
     }
}

Why? Because, it the user iterates on the read-only list of units while a new unit is added to the collection (by another thread) a ConcurrentModificationException is automatically raised.
A major issue with ConcurrentModificationException is that there is no certainty you will discover the problem during testing. You can imagine two threads one updating a collection and the other one iterating the collection. As long as the update is not performed while the other thread is iterating, everything is fine (no ConcurrentModificationException)! But, if for a reason or another the timing changes (e.g. in the user environment) and iterations are performed at the wrong time you will crash... Not a good thing and very high probability for this to happen :(

3. Copy on Write Solution.


The java.util.concurrent package provides two classes CopyOnWriteArrayList and CopyOnWriteArraySet which basically copy the underlaying collection each time a modification occurs (keeping the read-only view immutable). This approach can be generalized to any collection or map. For example:
class Dictionary {
    private HashMap<String, String> _definitions;
    public Map<String, String> getDefinitions() { // Read-only view.
        return Collections.unmodifiableMap(_definitions);
    }  
    void define(String word, String definition) {
        HashMap<String, String> definitions = new HashMap<String, String>(_definitions); // Copies collection.
        definitions.put(word, definition);
        _definitions = definitions;
    }
    ...
}

Still, this approach is very expensive especially for large collections as it requires a whole copy of the collection for each update.

4. Allowing safe concurrent modifications.


Another solution to this problem is to allow thread-safe modifications of the collection. For example, the Javolution (http://javolution.org) collections allow for concurrent modification as long as the collection elements (or map entries) are not removed. In other words, there is no need to "Copy on Write" unless deletion occur. A far less occurence. Often collection elements are never removed or if they are it is because the whole collection is cleared (in which case there is no need for copying the existing collection, just replacing with a new empty collection is just fine). Here is the units collection example using Javolution FastTable:
public class Unit {
     static FastTable<Unit> INSTANCES = new FastTable<unit>();
     public static List<Unit> getInstances() {
         return INSTANCES.unmodifiable();
     }
}

Here is the dictionary example:
public class Dictionary {
    private FastMap<String, String> _definitions = new FastMap<String, String>();
    public Map<String, String> getDefinitions() { // Read-only view.
        return _definitions.unmodifiable();
   }  
   void define(String word, String definition) {
       _definitions.put(word, definition);
   }
   void removeWord(String word) {
       FastMap<String, String> definitions = new FastMap<String, String>(_definitions); // Copies collection.
       definitions.remove(word);
       _definitions = definitions;
   }
   void clear() {
       _definitions = new FastMap<String, String>();
   }
}


For more information on Javolution collection see: javolution.util pkg
1 . At 7:56 AM on Mar 26, 2006, Artur Biesiadowski DeveloperZone Top 100 wrote:
  Click to reply to this thread Reply

Re: Read-Only Collections

It is funny that you gave examples 1-3 using JDK classes and in solution 4, instead of proposing ConcurrentHashMap, which is standard and works well with both additions and removes, you suddenly mention your library...
2 . At 11:22 AM on Mar 26, 2006, Alex Zhang wrote:
  Click to reply to this thread Reply

Re: Read-Only Collections

I am not getting your 2nd point. If you want the INSTANCE to be unmodifiable, why don't you make it private?

If this field is private, then when a thread is trying to insert a new unit to the list returned by getInstance() method, the UnsupportedException is thrown, but other threads that are iterating this list should not be affected at all.

3 . At 1:51 PM on Mar 26, 2006, Jean-Marie Dautelle DeveloperZone Top 100 wrote:
  Click to reply to this thread Reply

Re: Read-Only Collections

> It is funny that you gave examples 1-3 using JDK
> classes and in solution 4, instead of proposing
> ConcurrentHashMap, which is standard and works well
> with both additions and removes, you suddenly mention
> your library...


ConcurrentHashMap introduce problems of their own (e.g. potential blocking when reading, null values disallowed, etc.) and seem overkill for the only purpose of providing read-only views; especially if updates are not concurrent or are synchronized. That being said, it might be the only efficient solution if deletions are frequent (Note: An alternative solution to deletion with FastMap is to set the map value to null instead of removing the entry).

The ConcurrentHashMap API states about iterators:
They do not throw ConcurrentModificationException. However, iterators are designed to be used by only one thread at a time.

Not sure how to interpret the last sentence...
Jean-Marie Dautelle - Marlboro, MA
-- Javolution: Everything should be made as simple as possible... -- JScience: But not simpler!
4 . At 2:08 PM on Mar 26, 2006, Jean-Marie Dautelle DeveloperZone Top 100 wrote:
  Click to reply to this thread Reply

Re: Read-Only Collections

> I am not getting your 2nd point. If you want the
> INSTANCE to be unmodifiable, why don't you make it
> private?
>

We don't want the collection to be modifiable by the client directly. But indirect updates through the class methods have to be supported (encapsulation). In other words, INSTANCE can be private and still modifiable by any thread (in a controlled manner).
Jean-Marie Dautelle - Marlboro, MA
-- Javolution: Everything should be made as simple as possible... -- JScience: But not simpler!
5 . At 2:02 AM on Mar 27, 2006, Artur Biesiadowski DeveloperZone Top 100 wrote:
  Click to reply to this thread Reply

Re: Read-Only Collections

> The ConcurrentHashMap API states about
> iterators:
They do not throw
> ConcurrentModificationException. However, iterators
> are designed to be used by only one thread at a
> time.

> Not sure how to interpret the last sentence...

It means that you should not use particular instance of iterator from multiple threads at once.
6 . At 3:33 AM on Mar 27, 2006, Sebastian Mueller DeveloperZone Top 100 wrote:
  Click to reply to this thread Reply

Re: Read-Only Collections

> ... you suddenly mention
> your library...

... how surprising, Jean-Marie is mentioning his library?!
at least it took him more than 3 paragraphs until he mentions his library.

Now for something constructive ;-)

How about the following solution. I don't like solution number 3 because it claims to return a "view" instance, which actually is not a view (you cannot hold a reference to it, because it will at some point in time become invalid - that's not the idea of a view IMHO.) However one can rectify this easily, I would say:

 public class InvalidationList<T> implements List<T> {
  private final List<T> originalList;
  private int modCount;
 
  public InvalidationList(List<T> originalList) {
    this.originalList = originalList;
  }
 
  public boolean add(T o) {
    synchronized (this) {
      boolean b = originalList.add(o);
      modCount++;
      return b;
    }
  }
 
  public int size() {
    return originalList.size();
  }
 
  // more delegates like add... and size
 
  public List<T> unmodifiable(){
    return new InnerList(this);
  }
 
  static final class InnerList<T> implements List<T> {
    private List<T> delegate;
    private final InvalidationList<T> parentList;
    private int modCount;
 
    public InnerList(InvalidationList<T> parent) {
      parentList = parent;
      invalidate();
    }
 
    public int size() {
      checkInvalidation();
      return delegate.size();
    }
 
    private void checkInvalidation() {
      if (parentList.modCount > this.modCount) {
        invalidate();
      }
    }
 
    private void invalidate() {
      synchronized (parentList) {
        this.modCount = parentList.modCount;
        delegate = Collections.unmodifiableList(new ArrayList(parentList.originalList));
      }
    }
 
    
    // more delegates.... like size();
    
  }
}
 



What do you think?
yWorks - the diagramming company yFiles - graph layout library yGuard - Ant Java Obfuscator
7 . At 6:19 PM on Mar 27, 2006, Mike Cherichetti DeveloperZone Top 100 wrote:
  Click to reply to this thread Reply

Re: Read-Only Collections

An easy way to solve this is to return a clone of the mutable list that is unmodifiable.

That will work well for small lists, but not for huge lists. You really need to think about what you're doing though if you're considering returning a huge list for a user to iterate over the whole thing. If they really need to do that, I think it's better to provide some kind of filtering/querying/paging mechanism so you can return a new temporary list with a subset of the data. In fact that's probably what they're trying to build because you are just giving them this huge list that they can't consume well.

Either way, you will avoid iterators from blowing up in a multi-threaded app.

Also, I don't think that UnsupportedOperationException being thrown is a problem. If your users can't figure that out from your docs, make better docs or sell them consulting/training services :)
8 . At 10:44 AM on Mar 29, 2006, Werner Keil wrote:
  Click to reply to this thread Reply

Re: Read-Only Collections

>Also, I don't think that UnsupportedOperationException >being thrown is a problem. If your users can't figure >that out from your docs, make better docs or sell them >consulting/training services

That is a good point ! ;-)

Unlike the docs or ongoing support for a Domain Driven Framework I created around 1999 addressing some issues of Mutable vs. Immutable, too. I usually kept using it in training and consulting or projects at customers' sites.

The Source Forge Project (code-named "OdyssEE") therefore seems to have been "hidden" by SF due to lack of activity ? ;-/

I should have some backups left, and as we can see e.g. here (in all those frameworks and libs mentioned) there are others out there addressing similar demands...
9 . At 2:21 PM on Mar 29, 2006, Neel Kumar wrote:
  Click to reply to this thread Reply

Re: Read-Only Collections

I feel that read-only collections are just a special case
of the general need for an immutable flag. I would like to
see the Java language extended to bring const into the fold (it has been a reserved keyword since day one).
10 . At 12:55 AM on Mar 30, 2006, Jean-Marie Dautelle DeveloperZone Top 100 wrote:
  Click to reply to this thread Reply

Re: Read-Only Collections

FastMap has been enhanced to support concurrent entries removal when the map is marked as shared (making shared maps valid substitutes to ConcurrentHashMap and read-only views thread-safe in all cases). See util faq .
Jean-Marie Dautelle - Marlboro, MA
-- Javolution: Everything should be made as simple as possible... -- JScience: But not simpler!

thread.rss_message