在一个有问题的(遗留的)模型中保护自己不受并发的影响



我有一个图。该图由一个节点类组成,该节点类具有以下内容:

public abstract class AbstractNode{
    public Collection<AbstractNode> predecessors;
    public Collection<AbstractNode> successors;
    //accept methods for visitors
}

我最近添加了一个组件,它允许您从YAML文件导入配置。该组件读取YAML文件,并使用该节点类生成一个图。这段代码相当慢,在图上进行了大量操作,包括遍历一些前置节点、分析各种节点,以及决定如何更新其他节点的后续节点和/或前置节点。

我们现有的代码有一个服务,它每100毫秒轮询一次相同的图形,以使用访问者在我们的程序中生成错误列表。访问者实际上是一类对象,它将通过每个继承者和前任列表为每个对象访问一次。

这会导致并发修改异常。:(

我的选择似乎是:

  • 将轮询服务更新为事件驱动。
    • 我们从事件驱动策略转向了轮询策略,因为事件的复杂性越来越高。这里面有很多微妙的时间问题
    • 最适合模型的"纯度">
  • 更新问题轮询服务和我的新yaml导入程序,使它们都在线程工作队列上同步(显而易见的选择是UI线程,因为它们已经有了基于队列的实现(
    • 对UI框架的依赖性更强,如果UI框架不可用(并且我们的应用程序确实在无头命令行模式下运行(,那么怎么办
  • 实现使用可关闭可迭代项的集合,这些可迭代项锁定其源,直到进行close()调用或hasNext()返回false。这将允许我们要么阻止作者,直到读者完成。
    • 在可迭代项上搞砸。可能相当安全,因为实际上没有人再使用迭代器了,但这仍然是对契约的奇怪使用
  • 更新AbstractNode以使用CopyOnWriteArrayCollection作为其前置器和后续器的备份集/列表
    • List<String> predecessors = new CopyOnWriteArrayList<>()替换机上友好POJO List<String> predecessors = new ArrayList<>()代码
    • 需要额外的序列化程序配置和/或生成讨厌的XML/JSON
  • 通过将图突变操作推送到AbstractNode类上,将读取与写入模型分离,并替换getSuccessors/Precessors以返回防御副本和/或不可变集合(例如PCollections中的集合(
    • 需要大量的代码来解决概念上非常小的问题
    • 需要更新大量使用此图的位置(期望标准可变集合使用AbstractNode上的方法(

我真正想要的是一个集合框架,它是围绕组合而不是继承构建的。

将其转化为一秒钟的咆哮,并借助(大量(后见之明,它非常清楚地认识到,当面临创建抽象类及其多个实现的选择时,或者一个委托依赖项的类(读作:由其依赖项组成(时,后者是普遍可取的。

没有图书馆允许我做类似的事情吗

private final Collection<AbstractNode> predecessors = Collections.create(
    DuplicationPolicies.ForbidDuplicates,
    Orders.InsertionOrder,
    Concurrency.ThrowOnConcurrentModification
);

对于LinkedHashSet<>

private final Collection<AbstractNode> predecessors = Collections.create(
    DuplicationPolicies.AllowDuplicates,
    Orders.InsertionOrder,
    Concurrency.CopyOnWrite
);

对于CopyOnWriteArrayList<>

有了这样的系统,从一个厌恶并发的实现(如ArrayList(切换到一个容忍并发的实现,(如CopyOnWrite列表或Shared/Exclusive锁定列表(对我来说(可能(相当简单。

java中还没有现成的复合集合,但您可以使用标准java集合和一些作为类成员的附加对象轻松地手工实现它们。

由于您总是使用Orders.InsertionOrder策略,所以类似列表的基本集合最适合您。您可以使用CopyOnWriteArrayList作为实现Concurrency.CopyOnWrite策略的基本集合,使用简单的ArrayList来实现Concurrency.ThrowOnConcurrentModification

对于DuplicationPolicies,用单个bool canAddElem(collection, elem)方法附加对象就足够了。

类似的东西:

public class CompositeCollection extends Collection<AbstractNode>
{
    private Collection<AbstractNode> baseCollection;
    private filter;
    public CompositCollection(DuplicationPolicies dPolicy, Concurrency cPolicy)
    {
        if(dPolicy == DuplicationPolicies.AllowDuplicates)
        {
            filter = new AllowDuplicatesFilter();
        }
        else
        {
            filter = new ForbidDuplicatesFilter();
        }
        if(cPolicy == Concurrency.Concurrency.CopyOnWrite)
        {
            baseCollection = new CopyOnWriteArrayList<AbstractNode>();
        }
        else
        {
            baseCollection = new ArrayList<AbstractNode>();
        }
    }
    public bool add(AbstractNode node)
    {
        if(!filter->canAddElem(baseCollection, node)) {return false; }
        return baseCollection->add(node);
    }
    ...
};

相关内容

最新更新