简体   繁体   中英

How do I synchronize access to a member of a different class?

I'm trying to figure out how to synchronize read/write access to a synchronized list from a different class.

A small example: I have a synchronized list in one class ListProvider and I access it in a different class Filter . As the name suggests, this class performs some filtering based on a (in)validation check isInvalid .

The filter method first gets the list reference, then collects the entries to remove in a temporary list to not run into concurrent modification issues, and finally removes the entries from the list:

public class Filter {

    ListProvider listProvider;

    ...

    public void filter() {
        List<String> listProviderList = listProvider.getList();

        List<String> entriesToRemove = new ArrayList<>();

        // collect
        for (String entry : listProviderList)
            if (isInvalid(entry)) {
                entriesToRemove.add(entry);
            }
        }

        // remove
        for (String entry : entriesToRemove) {
            listProviderList.remove(entry);
        }       
    }
}

My question: How can I make sure that no other thread modifies the list while filter does its reading and writing?

If it were Filter 's own list, I'd just do:

synchronized(myList) {
    // collect
    // remove
}

but in this case I'm not sure what to use as a monitor.

but in this case I'm not sure what to use as a monitor.

To create a monitor for a specific task, it is a good pattern to use a private final Object :

 private final Object listUpdateLock = new Object();
 ...
 synchronized(listUpdateLock) {
    ...
 }

It's important to make sure that ListProvider is private and that all accesses to the list are done within a synchronized block -- even if only reading from it.

In this case, you are updating the list, you could create a temporary list and then replace it when you are done. I'm not sure you can do that with ListProvider however. Then you could just make the list volatile .

Here it seems like you should use a lock . A lock is like synchronized but it's a bit more flexible. It doesn't require a surrounding block and it has some extended features. There are also some different kinds of locks. ReentrantLock is much like synchronized.

public class ListProvider<E> {
    private final List<E> theList = new ArrayList<E>();
    private final ReentrantLock listLock = new ReentrantLock();

    public final List<E> lockList() {
        listLock.lock();
        return theList;
    }

    public final void unlockList() {
        listLock.unlock();
    }
}

/* somewhere else */ {

    List<E> theList = listProvider.lockList();

    /*
     * perform
     * multiple
     * operations
     *
     */

    listProvider.unlockList();
}

The main differences between this and synchronized are:

  • The actual locking mechanism is hidden. This is good for abstraction; however,
  • Clients must remember to unlock explicitly whereas a synchronized monitor exit is at a block delimiter.

There is a lock called ReentrantReadWriteLock which you might find useful because multiple threads can read simultaneously. ReadWriteLock explains how it works.

Do not iterate over original list, but create a copy of it to find invalid elements. When you are done with filtering you can remove invalid elements from original list safely:

public class Filter {

    ListProvider listProvider;

    ...

    public void filter() {
        List<String> listProviderCopy = new ArrayList<>(listProvider.getList());

        List<String> entriesToRemove = new ArrayList<>();

        // collect
        for (String entry : listProviderCopy)
            if (isInvalid(entry)) {
                entriesToRemove.add(entry);
            }
        }

        listProvider.getList().removeAll(entriesToRemove);
    }
}

You may want to use SynchronizedList

List<String> list = new ArrayList<>();

List<String> synch = Collections.synchronizedList(list);

more

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM