我想将以下代码转换为适合多线程环境的代码。
List<Observer> list = new ArrayList<>();
public void removeObserver(Observer p) {
for (Observer observer: list) {
if (observer.equals(p)) {
list.remove(observer);
break;
}
}
}
public void addObserver(Observer p) {
list.add(p);
}
public void notifyObserver(Event obj) {
for (Observer observer: list) {
observer.notify(obj);
}
}
无疑,最简单的方法之一是添加synchronized
关键字,该关键字确保只有一个线程可以运行该逻辑,从而确保结果正确。
但是,有没有更好的方法来解决此问题。我进行了某种研究,发现可以使用Collections.synchronizedList
,并且还注意到这样的list.iterator is not thread-safe
,因此应避免直接使用forEach循环或迭代器unless I do a synchronized (list)
我只是不想使用同步,并考虑是否还有另一种可能的方法。这是我的第二次尝试。
synchronized (list)
我只想问一下我的第二次尝试是否是线程安全的?另外,有没有比我提议的第二种方法更好的方法呢?
当然,最简单的方法之一是添加synced关键字,这确保只有一个线程可以运行逻辑,从而确保结果正确。
这是正确的。
但是,有没有更好的方法来解决此问题?
我不这么认为。
让我们看看您的第二次尝试:
List<Observer> list = Collections.synchronizedList(new ArrayList<Observer>()); // which is thread safe
public void removeObserver(Observer p) {
// as the list may get modify, I create a copy first
List<Observer> copy = new CopyOnWriteArrayList(list);
for (Observer observer: copy) {
if (observer.equals(p)) {
// but now, no use of iterator
list.remove(observer); // remove it from the original copy
break;
}
}
}
public void addObserver(Observer p) {
list.add(p);
}
public void notifyObserver(Event obj) {
List<Observer> copy = new CopyOnWriteArrayList(list);
// not use iterator, as thread safe list's iterator can be thread unsafe
// and for-each loop use iterator concept
for (Observer observer: copy) {
observer.notify(obj);
}
}
是的,它是线程安全的。有一定限制。
List<Observer> list = Collections.synchronizedList(new ArrayList<Observer>());
// which is thread safe
这里有三个问题:
您正在创建列表的副本。这是一个public void removeObserver(Observer p) {
// as the list may get modify, I create a copy first
List<Observer> copy = new CopyOnWriteArrayList(list);
...
操作。
O(N)
构造函数将迭代CopyOnWriteArrayList
...,并且由list
创建的列表的迭代不是原子/线程安全的,因此您具有竞争条件。
synchronizedList
相对于CopyOnWriteArrayList
没有实际好处。 ArrayList
对象是本地的并且是线程限制的,因此它不必是线程安全的。
总之,这不是线程安全的,仅使原始方法同步就更昂贵。
(我正在研究可能的改进。我会回到这个问题。)