问题描述
我调用了RMI方法,它位于同步块中。这样的事情,其中方法appendEntries
是被称为的RMI方法:
public void run() {
synchronized(matchIndex.get(followerId)) {
ArrayList<Entry> reqs = new ArrayList<>();
for (int i = matchIndex.get(followerId) + 1; i <= log.lastIndex(); i++) {
reqs.add(log.get(i));
}
try {
answer = server.serverList.get(followerId).appendEntries(reqs);
if (answer.isSuccessful()) {
matchIndex.replace(followerId,matchIndex.get(followerId) + reqs.size());
} else {
System.out.println("Not Successfull.");
}
} catch (Exception e) {
e.printstacktrace();
}
}
}
此线程正在等待RMI方法的答案时,是否释放matchIndex.get(followerId)
中的锁?
为了更好的上下文,我之所以这样问是因为,显然,在使用各种线程且没有未成功回答的情况下,出现了一个随机点,即两个线程在为同一个followerId
调用appendEntries,然后在{ {1}},这不应该发生,我怀疑是原因。
如果您需要进一步的说明,我正在为类项目实现共识算法Raft。如果您不熟悉它,那么基本上这段简化的代码就是“领导者”逻辑的一部分,他必须将日志中的条目发送给他的“跟随者”。领导者和跟随者的日志最终必须保持一致。这段代码在一个线程上,当“领导者”希望将其日志条目发送到特定的跟随者时,该线程将被调用,但是他对每个跟随者一次都不应多次调用reqs
方法。 appendEntries
是领导者为每个关注者知道的最后一个条目的位置。
我希望它不是太多或太少的信息,这是我使用该网站多年后的第一个堆栈溢出问题,我们将不胜感激。
解决方法
正如@NathanHughes指出的那样,我的问题是我在具有锁定的对象上使用了replace方法,并且弄乱了同步对象。我创建了一个新的对象数组,专门用于锁定,现在可以完美地工作了。