Re: ArrayList - Reading and writing
Daniele Futtorovic wrote:
On 2008-07-15 16:07 +0100, Jimmie Tyrrell allegedly wrote:
On Jul 15, 9:48 am, shakah <shakahsha...@gmail.com> wrote:
On Jul 15, 9:38 am, Jimmie Tyrrell <osk...@gmail.com> wrote:
Got a Java-y question:
I have a loop that executes periodically. The loop iterates over an
Array List, and processes each item.
Randomly, a UDP socket will receive some data, which is then appended
to the Array List.
The problem, naturally, is that my Iterator will throw an exception if
data is received while I'm Iterating over the ArrayList.
Catching the exception is okay - but it occurs while Iterating. I'd
prefer the Iteration process to go untouched, and instead maybe
receive the Exception while _writing_ the data. I could then cache
it, or simply ignore it, whatever.
Any suggestions on how to achieve this? Need to see some code to
understand the problem?
Generally you'd synchronize read and write access to the array list,
e.g.:
// ...reader code
synchronized(your_array_list) {
for(java.util.Iterator i=your_array_list.iterator(); i.hasNext(); )
{
your_object tmp = (your_object) i.next() ;
}
}
// ...writer code (UDP)
while(we_wait_for_udp_packets) {
// ...got a packet
synchronized(your_array_list) {
your_array_list.add(new your_object(packet)) ;
}
}
That was perfect. I had tried using synchronized before - wasn't
aware that _both_ operations needed to be synchronized. It seems
overtly logical now :)
Thanks for the help!
The problem with shakah's approach is that it monopolises the List
Object during the whole process of Iteration -- which may go down well,
but which may also pose some problems.
It would be better to iterate over a copy. You'd still synchronise the
process of copying, as well as the process of adding.
For instance (non-generic code for the sake of simplicity):
List myQueue = ...;
/* adding */
synchronized( someLock ){
myQueue.add(newObject);
}
/* end adding */
/* iterating */
List copy;
synchronized( someLock ){
copy = java.util.Collections.unmodifiableList(myQueue);
}
for(Iterator it = copy.iterator(); it.hasNext();){
//do something involving it.next();
}
/* end iterating */
Note that copying the List doesn't involve copying its /content/.
And what you did doesn't copy the list either, it just wraps it. To copy
it you'd actually have to use new ArrayList(someQueue); The thing is,
that this process ALSO iterates over the whole list (although only for a
fast reference copy).
I had just made a suggestion that is another way to solve the OPs
problem, using new Java 1.5 Concurrency API features.
The approach to take depends on the size of the list, and the required
performance characteristics of the UDP handler.
--
Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>