我正在使用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);
当一个线程打开一个迭代器,另一个正在修改同一个顶点时,可能会发生异常。我该如何解决这个异常?
答案 0 :(得分:0)
在以前的版本中,storage.batch-loading
仅用于单线程操作。 http://thinkaurelius.github.io/titan/wikidoc/0.4.4/Graph-Configuration.html
在Titan 1.0中可能仍然如此。
答案 1 :(得分:0)
我对泰坦并不熟悉,但如果我遇到多线程问题,我会尝试分析哪里 并发访问发生了,我可以同步并发访问的最小区域是什么, 或者有哪些更好的替代方案(例如:线程安全的收集替代方案,其他访问方式)。
此代码模拟此错误:
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()。有(”key“,key).vertices()”返回基于Collection的值你可以使用它的toArray(new Type [0]) 并通过它的副本进行迭代。在此示例中,将main中的迭代周期修改为: for(String s:data.toArray(Mirror.emptyStringArray)) s.length();
解决问题,但是如果实现后面的Collection不管理并发访问,则可能仍然存在并发问题。 我的意思是:一个例子:一个类型声明它根本不包含空值,但是如果在一个线程中调用了一个删除而你在另一个调用了另一个(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();