安全使用 WeakReference
Using WeakReference Safely
假设我有一个 class Publisher
,其中 Subscriber
个对象的列表存储在 WeakReference<>
的列表中
public interface Subscriber {
void update();
}
public class Publisher {
private final List<WeakReference<Subscriber>> subscribers = new CopyOnWriteArrayList<>();
public void subscribe(final Subscriber subscriber) {
subscribers.add(new WeakReference<>(subscriber));
}
public void publish() { ...
在调用 Publisher::subscribe
和稍后调用 Publisher::publish
之间,弱引用列表中的 Subscriber
可能已被垃圾回收,所以我需要检查它是否是null
在使用之前。
我的问题是下面的代码是否是 publish
的安全实施?
public void publish() {
//filter out garbage collected items
subscribers = subscribers.stream()
.filter(sub -> sub.get() != null)
.collect(Collectors.toList());
//use the remaing objects
for (final WeakReference<Subscriber> sub : subscribers) {
sub.get().update());
}
}
垃圾收集器是否可能在过滤 subscribers
和调用 Subscriber::update
之间销毁了另一个对象?
我应该在更新时进行第二次 null
检查吗?
for (final WeakReference<Subscriber> sub : subscribers) {
if (sub.get() != null) {
sub.get().update());
}
}
您建议的第二次无效检查也不够好,因为第一次调用 get()
可能 return 一个非空值,第二次调用可能 return null
。我建议:
for (WeakReference<Subscriber> subRef : subscribers) {
Subscriber sub = subRef.get();
if (sub != null) {
sub.update();
}
}
或使用 Java 8 的流(未测试):
subscribers
.stream()
.map(WeakReference::get)
.filter(s -> s != null)
.forEach(Subscriber::update);
假设我有一个 class Publisher
,其中 Subscriber
个对象的列表存储在 WeakReference<>
public interface Subscriber {
void update();
}
public class Publisher {
private final List<WeakReference<Subscriber>> subscribers = new CopyOnWriteArrayList<>();
public void subscribe(final Subscriber subscriber) {
subscribers.add(new WeakReference<>(subscriber));
}
public void publish() { ...
在调用 Publisher::subscribe
和稍后调用 Publisher::publish
之间,弱引用列表中的 Subscriber
可能已被垃圾回收,所以我需要检查它是否是null
在使用之前。
我的问题是下面的代码是否是 publish
的安全实施?
public void publish() {
//filter out garbage collected items
subscribers = subscribers.stream()
.filter(sub -> sub.get() != null)
.collect(Collectors.toList());
//use the remaing objects
for (final WeakReference<Subscriber> sub : subscribers) {
sub.get().update());
}
}
垃圾收集器是否可能在过滤 subscribers
和调用 Subscriber::update
之间销毁了另一个对象?
我应该在更新时进行第二次 null
检查吗?
for (final WeakReference<Subscriber> sub : subscribers) {
if (sub.get() != null) {
sub.get().update());
}
}
您建议的第二次无效检查也不够好,因为第一次调用 get()
可能 return 一个非空值,第二次调用可能 return null
。我建议:
for (WeakReference<Subscriber> subRef : subscribers) {
Subscriber sub = subRef.get();
if (sub != null) {
sub.update();
}
}
或使用 Java 8 的流(未测试):
subscribers
.stream()
.map(WeakReference::get)
.filter(s -> s != null)
.forEach(Subscriber::update);