【问题标题】:Titan ConcurrentModificationExceptionTitan ConcurrentModificationException
【发布时间】:2015-12-03 10:02:41
【问题描述】:

我正在使用 Titan-1.0.0 测试批量加载

我在我的配置文件中设置了 storage.batch-loading=true

我在我的 java 程序中使用 TitanBlueprintsTransaction 来提高图形加载性能,它是多线程的。

我在加载过程中遇到 ConcurrentModificationException 异常,我的代码是这样的

在线程#1中,像这样使用titan复合索引搜索顶点

Iterator<TitanVertex> it = tx.query().has("key", key).vertices().iterator();
TitanVertex vtx = it.next();

在线程#2中,尝试在同一顶点添加边

tx.getVertex(v).addEdge(edgeLabel, target);

当一个线程打开一个迭代器,而另一个线程对同一个顶点进行修改时,可能会发生异常。我该如何解决这个异常?

【问题讨论】:

  • tx.query().has("key", key).vertices()tx.getVertex(v) 的返回类型是什么??
  • Iterable 和 TitanVertex
  • 您能否发布更多代码,例如创建和完成交易的位置?堆栈跟踪怎么样?

标签: java multithreading titan


【解决方案1】:

在以前的版本中,storage.batch-loading 仅用于单线程操作。 http://thinkaurelius.github.io/titan/wikidoc/0.4.4/Graph-Configuration.html 听起来在 Titan 1.0 中可能仍然如此。

【讨论】:

  • 实际上,将批量加载选项设置为 false 并没有什么不同。
【解决方案2】:

我对泰坦不熟悉,但如果我遇到多线程问题,我会尝试分析在哪里 发生了并发访问,我可以同步并发访问的最小区域是什么, 或有什么更好的替代方案(例如:线程安全的 Collection 替代方案,其他访问方式)。

此代码模拟此错误:

public class ConcurrentMod
{

    public static <C extends Collection<String>> void fillCollectionTestData(C coll)
    {
        for(int i=0;i<10000;++i)
            coll.add(String.valueOf(i));
    }

    public static void main(String[] args)
    {
        final List<String> data = new ArrayList<>();
        fillCollectionTestData(data);

        new Thread()
        {
            public void run()
            {
                //heavy opertaion for an array
                for(int i=0;i<100;++i)
                    data.remove(i);
            }
        }.start();

        for(String s:data)
            s.length();
    }
}

常规列表(ArrayList、LinkedList)无法处理并发访问。 但正如我测试的那样,即使是 Vector 的迭代器也无法处理这种情况(WAT?很高兴知道)。 因此,如果您可以修改实现代码,则没有简单的方法可以简单地将 Collection 类型更改为另一种并发安全类型。

另一个思路是:如果 "tx.query().has("key", key).vertices()" 返回值基于 Collection 你可以使用它的 toArray(new Type[0]) 并遍历它的副本。在此示例中,将 main 中的迭代周期修改为: for(String s:data.toArray(Mirror.emptyStringArray)) s.length();

解决了问题,但如果实现背后的集合不管理并发访问,则可能仍然存在并发问题。 我的意思是:一个例子:一个类型声明它根本不包含空值,但是如果在一个线程中调用了 delete 并且你在另一个线程中调用了 toArray(T) 你也许可以面对一个空值的数组!因为你看到了一个不完整的操作视图。删除一半完成但一致性未恢复,因为删除未完全完成。 如果你不能确定背后的实现处理这个你需要使用外部同步:

    for(int i=0;i<100;++i)
        //other threads can access array between 2 heavy array shifting
        synchronized(data)
        {
            data.remove(i);
        }

    //and synchronize during array copy
    String[] tmp = null;
    synchronized(data)
    {
        tmp = data.toArray(Mirror.emptyStringArray);
    }

    for(String s:tmp)
        s.length();

【讨论】:

    猜你喜欢
    • 2016-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-06
    • 2023-03-03
    相关资源
    最近更新 更多