安全使用 Wea​​kReference

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);