I found a class containing a List which was updated infrequently but iterated regularly (rendered as a table in a GUI). The old code synchronized on the List to return a copy for iteration in order to prevent a ConcurrentModificationException being thrown if an update occurred while the List was being iterated.
The new code uses a CopyOnWriteArrayList from the java.util.concurrent package to relieve the user of having to write thread safe boilerplate code around mutator and traversal access.
Using Collections.unmodifiableList enforces that the copy returned is read-only (any attempts to modify the list will throw UnsupportedOperationException).
Old code:
private List<Foo> myList = new ArrayList<Foo>();

public void add(Foo f)
{
   synchronized(myList)
   {
       myList.add(f);
   }
}

public List<Foo> getListCopy()
{
   synchronized(myList)
   {
       return new ArrayList<Foo>(myList);
   }
}
New code:
private List<Foo> myList = new CopyOnWriteArrayList<Foo>();

public void add(Foo f)
{
   myList.add(f);
}

public List<Foo> getListCopy()
{
   return Collections.unmodifiableList(myList);
}
Note that CopyOnWriteArrayList performs an array copy on every modification. It should be used when reads outnumber writes to the List. If this is not the case and you can measurably prove that writes to the list are causing performance issues then you should manually synchronise reads and writes to a normal ArrayList instead.