[英]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
. 一个小例子:我在一个类
ListProvider
有一个同步列表,并在另一个类Filter
访问它。 As the name suggests, this class performs some filtering based on a (in)validation check isInvalid
. 顾名思义,此类基于(
isInvalid
)验证检查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: filter
方法首先获取列表引用,然后收集要删除的条目到临时列表中,以免遇到并发修改问题,最后从列表中删除条目:
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? 我的问题:如何确保在
filter
读写列表的同时没有其他线程修改列表?
If it were Filter
's own list, I'd just do: 如果它是
Filter
自己的列表,我将这样做:
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
是一个很好的模式:
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. 重要的是要确保
ListProvider
是private
并且对列表的所有访问都在synchronized
块内完成-即使仅从其中读取也是如此。
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. 我不确定您可以使用
ListProvider
做到这ListProvider
。 Then you could just make the list volatile
. 然后,您可以使列表
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.
ReentrantLock很像同步。
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: 此和同步之间的主要区别是:
There is a lock called ReentrantReadWriteLock which you might find useful because multiple threads can read simultaneously. 有一个称为ReentrantReadWriteLock的锁,由于多个线程可以同时读取,因此您会发现它很有用。 ReadWriteLock explains how it works.
ReadWriteLock解释了它是如何工作的。
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);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.