views:

145

answers:

5

Will the following code snippet of a synchronized ArrayList work in a multi-threaded environment?

class MyList {
    private final ArrayList<String> internalList = new ArrayList<String>();

    void add(String newValue) {
        synchronized (internalList) {
            internalList.add(newValue);
        }
    }

    boolean find(String match) {
        synchronized (internalList) {
            for (String value : internalList) {
                if (value.equals(match)) {
                    return true;
                }
            }
        }

        return false;
    }
}

I'm concerned that one thread wont be able to see changes by another thread.

+2  A: 

It will work fine, because all access to the list is synchronized. Hovewer, you can use CopyOnWriteArrayList to improve concurrency by avoiding locks (especially if you have many threads executing find).

axtavt
(And not many `add`/`set`/`remmove` (*length) calls.)
Tom Hawtin - tackline
+2  A: 

This should work, because synchronizing on the same object establishes a happens-before relationship, and writes that happen-before reads are guaranteed to be visible.

See the Java Language Specification, section 17.4.5 for details on happens-before.

meriton
Thanks, so another thread is guaranteed to see any changes because of the `synchronize` flushes the array list state?
Pool
Actually, this is not a problem with flushing, but with optimizations done by the JIT. The JIT assumes that fields are only modified by the current thread, unless the fields are accessed within a synchronized block, or are volatile. For details, check the JLS.
meriton
+3  A: 

It will work, but better solution is to create a List by calling Collections.synchronizedList().

fastcodejava
+5  A: 

Your code will work and is thread-safe but not concurrent. You may want to consider using ConcurrentLinkedQueue or other concurrent thread-safe data structures like ConcurrentHashMap or CopyOnWriteArraySet suggested by notnoop and employ contains method.

class MyList {
    private final ConcurrentLinkedQueue<String> internalList = 
         new ConcurrentLinkedQueue<String>();

    void add(String newValue) {
        internalList.add(newValue);
    }

    boolean find(String match) {
        return internalList.contains(match);
    }
}
Chandra Patni
You should also consider using `ConcurrentHashMap` or `CopyOnWriteArraySet`, as those would significantly increase your `find` operation
notnoop
Apologies that my code was a bit simplified. The actual code stores objects and need to perform custom action.
Pool
A: 

You may want to consider using a Set(Tree or Hash) for your data as you are doing lookups by a key. They have methods that will be much faster than your current find method.

HashSet<String> set = new HashSet<String>();
Boolean result = set.contains(match); // O(1) time
Milhous