Sabobin
Sabobin

Reputation: 4276

How can I stop two threads colliding when accessing java ArrayList?

I have two threads which both need to access an ArrayList<short[]> instance variable.

One thread is going to asynchronously add short[] items to the list via a callback when new data has arrived : void dataChanged(short[] theData)

The other thread is going to periodically check if the list has items and if it does it is going to iterate over all the items, process them, and remove them from the array.

How can I set this up to guard for collisions between the two threads?

This contrived code example currently throws a java.util.ConcurrentModificationException

//instance vairbales
private ArrayList<short[]> list = new ArrayList<short[]>();

//asynchronous callback happening on the thread that adds the data to the list
void dataChanged(short[] theData) {
    list.add(theData);
}

//thread that iterates over the list and processes the current data it contains
Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {

        while (true) {

            for(short[] item : list) {
                //process the data 
            }

            //clear the list to discared of data which has been processed. 
            list.clear(); 

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
});

Upvotes: 1

Views: 1666

Answers (6)

waldol1
waldol1

Reputation: 1881

http://docs.oracle.com/javase/7/docs/api/java/util/Collections.html#synchronizedList%28java.util.List%29

You can ask the Collections class to wrap up your current ArrayList in a synchronized list.

Upvotes: 0

fortran
fortran

Reputation: 76077

You can use synchronized blocks, but I think the best solution is to not share mutable data between threads at all.

Make each thread to write in its own space and collect and aggregate the results when the workers are finished.

Upvotes: 0

Alan
Alan

Reputation: 3417

Take a look at Java's synchronization support.

This page covers making a group of statements synchronized on a specified object. That is: only one thread may execute any sections synchronized on that object at once, all others have to wait.

Upvotes: 0

Matt Wolfe
Matt Wolfe

Reputation: 9284

You might look into a blockingqueue for this instead of an arraylist.

Upvotes: 2

Mike Samuel
Mike Samuel

Reputation: 120526

You might want to use a producer consumer queue like an ArrayBlockingQueue instead or a similar concurrent collection.

The producer–consumer problem (also known as the bounded-buffer problem) is a classic example of a multi-process synchronization problem. The problem describes two processes, the producer and the consumer, who share a common, fixed-size buffer used as a queue. The producer's job is to generate a piece of data, put it into the buffer and start again. At the same time, the consumer is consuming the data (i.e., removing it from the buffer) one piece at a time. The problem is to make sure that the producer won't try to add data into the buffer if it's full and that the consumer won't try to remove data from an empty buffer.

One thread offers short[]s and the other take()s them.

Upvotes: 7

assylias
assylias

Reputation: 328737

The easiest way is to change the type of list to a thread safe list implementation:

private List<short[]> list = new CopyOnWriteArrayList<short[]>();

Note that this type of list is not extremely efficient if you mutate it a lot (add/remove) - but if it works for you that's a simple solution.

If you need more efficiency, you can use a synchronized list instead:

private List<short[]> list = Collections.synchronizedList(new ArrayList<short[]>());

But you will need to synchronize for iterating:

synchronized(list) {
    for(short[] item : list) {
        //process the data 
    }
}

EDIT: proposals to use a BlockingQueue are probably better but would need more changes in your code.

Upvotes: 5

Related Questions