$ java -version
java version "1.7.0_65"
Java(TM) SE Runtime Environment (build 1.7.0_65-b17)
Java HotSpot(TM) 64-Bit Server VM (build 24.65-b04, mixed mode)
Neo4j版本= 2.2.6
。
两个线程试图访问同一毫秒内的同一个节点,并迭代大约500多个关系。结果是两个线程都永远挂起。
可能有什么修复方法或正确方法? (除此之外,"不要做两次。")
更新
使用JStack获取线程转储,看起来它与neo4j
无关,但与HashSet
/ HashMap
有关。请参阅下面的更新....
日志输出 - 记下线程序列1& 2:
17:12:12.798 (neo4j-ro-pool-2) DEBUG [db.neo4j.Neo4jDao] - Open neo4j tx
17:12:12.798 (neo4j-ro-pool-2) DEBUG [db.neo4j.Neo4jDao] - Getting Node for [XYZ]
17:12:12.798 (neo4j-ro-pool-1) DEBUG [db.neo4j.Neo4jDao] - Open neo4j tx
17:12:12.798 (neo4j-ro-pool-1) DEBUG [db.neo4j.Neo4jDao] - Getting Node for [XYZ]
17:12:12.800 (neo4j-ro-pool-2) DEBUG [db.neo4j.Neo4jDao] - Got Node[284172852]
17:12:12.800 (neo4j-ro-pool-2) DEBUG [db.neo4j.Neo4jDao] - Getting Relationships for Node[284172852]
17:12:12.800 (neo4j-ro-pool-1) DEBUG [db.neo4j.Neo4jDao] - Got Node[284172852]
17:12:12.800 (neo4j-ro-pool-1) DEBUG [db.neo4j.Neo4jDao] - Getting Relationships for Node[284172852]
Neo4jDao
内的代码:
public Data addNamesToData(Data data) {
LOG.debug("Open neo4j tx");
try (Transaction tx = graphdb.beginTx()) {
LOG.debug("Getting Node for [{}]", data);
Node node = getNode(data);
LOG.debug("Got {}", node);
if (node == null) {
LOG.debug("Existing Node for [{}] NOT FOUND", data);
tx.success();
return data;
}
addNames(node, data);
tx.success();
return data;
} finally {
LOG.debug("Close neo4j tx");
}
}
private Data addNames(Node node, Data data) {
LOG.debug("Getting Relationships for {}", node);
Iterable<Relationship> rels = node.getRelationships(RelType.HAS_NAME_DATA, Direction.OUTGOING);
int count = 0;
for (Relationship rel : rels) { // Approx 500+ Relationships
String name = NodeUtils.getNameFromNode(rel.getEndNode());
LOG.trace("Adding Name [{}] to Data [{}]", name, data );
data.addName(name);
count++;
}
LOG.debug("Got {} Relationships for [{}]", count, node);
return data;
}
Data.addName():
private final Set<String> nameSet = new HashSet<>();
public void addName(String name) {
if(name != null) {
this.nameSet.add(name);
}
}
更新
使用JStack获取线程转储,看起来它与neo4j
无关,但与HashSet
/ HashMap
有关。
注意: Data
的实例在每个帖子上都不同....
"neo4j-ro-pool-2" prio=10 tid=0x00007f572c002000 nid=0x6ebf runnable [0x00007f4eb40d8000]
java.lang.Thread.State: RUNNABLE
at java.util.HashMap.put(HashMap.java:494)
at java.util.HashSet.add(HashSet.java:217)
at data.Data.addName(Data.java:162)
at db.neo4j.Neo4jDao.addNames(Neo4jDao.java:231)
at db.neo4j.Neo4jDao.addNamesToData(Neo4jDao.java:216)
at bus.subscriber.NamesSubscriber.handle(NamesSubscriber.java:39)
at bus.subscriber.NamesSubscriber.handle(NamesSubscriber.java:18)
at bus.adaptor.SubscriberAdaptor$Task.run(SubscriberAdaptor.java:102)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
Locked ownable synchronizers:
- <0x00007f5845c439d8> (a java.util.concurrent.ThreadPoolExecutor$Worker)
"neo4j-ro-pool-1" prio=10 tid=0x00007f572c001000 nid=0x6ebe runnable [0x00007f4eb3cd4000]
java.lang.Thread.State: RUNNABLE
at java.util.HashMap.put(HashMap.java:494)
at java.util.HashSet.add(HashSet.java:217)
at data.Data.addName(Data.java:162)
at db.neo4j.Neo4jDao.addNames(Neo4jDao.java:231)
at db.neo4j.Neo4jDao.addNamesToData(Neo4jDao.java:216)
at bus.subscriber.NamesSubscriber.handle(NamesSubscriber.java:39)
at bus.subscriber.NamesSubscriber.handle(NamesSubscriber.java:18)
at bus.adaptor.SubscriberAdaptor$Task.run(SubscriberAdaptor.java:102)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
Locked ownable synchronizers:
- <0x00007f58494161d8> (a java.util.concurrent.ThreadPoolExecutor$Worker)
使用this blog中的提示我已经确定哪个线程正在咀嚼CPU。
$ top -n1 -H | grep -m1 java
28350 ubuntu 20 0 95.143g 0.013t 2.383g R 99.9 45.7 1154:16 java
$ printf "%x\n" 28350
6ebe
从线程转储中我们看到nid=0x6ebe
是线程"neo4j-ro-pool-1"
。不确定这有什么帮助。