volatile多线程并不安全
Opened this issue · 2 comments
fsan42 commented
if (N > commitIndex) {
LogEntry entry = logModule.read(N);
if (entry != null && entry.getTerm() == currentTerm) {
commitIndex = N;
}
}
// 响应客户端(成功一半)
if (success.get() >= (count / 2)) {
// 更新
commitIndex = logEntry.getIndex();
// 应用到状态机
getStateMachine().apply(logEntry);
lastApplied = commitIndex;
log.info("success apply local state machine, logEntry info : {}", logEntry);
// 返回成功.
return ClientKVAck.ok();
} else {
// 回滚已经提交的日志.
logModule.removeOnStartIndex(logEntry.getIndex());
log.warn("fail apply local state machine, logEntry info : {}", logEntry);
// TODO 不应用到状态机,但已经记录到日志中.由定时任务从重试队列取出,然后重复尝试,当达到条件时,应用到状态机.
// 这里应该返回错误, 因为没有成功复制过半机器.
return ClientKVAck.fail();
}
这种涉及到多线程操作的变量比如commitIndex 虽然是 volatile修饰了 但是是不是仍然存在线程安全问题可能被一个旧的更小的值覆盖掉?而这里的赋值有很多先查询后写入的过程,那如果这里有问题,我们继续推断一下,是不是所有多线程操作的变量都有可能出现更新丢失?
Kakk22 commented
方法级别加了synchronized
kebukeYi commented
if (N > commitIndex) { LogEntry entry = logModule.read(N); if (entry != null && entry.getTerm() == currentTerm) { commitIndex = N; } } // 响应客户端(成功一半) if (success.get() >= (count / 2)) { // 更新 commitIndex = logEntry.getIndex(); // 应用到状态机 getStateMachine().apply(logEntry); lastApplied = commitIndex; log.info("success apply local state machine, logEntry info : {}", logEntry); // 返回成功. return ClientKVAck.ok(); } else { // 回滚已经提交的日志. logModule.removeOnStartIndex(logEntry.getIndex()); log.warn("fail apply local state machine, logEntry info : {}", logEntry); // TODO 不应用到状态机,但已经记录到日志中.由定时任务从重试队列取出,然后重复尝试,当达到条件时,应用到状态机. // 这里应该返回错误, 因为没有成功复制过半机器. return ClientKVAck.fail(); }
这种涉及到多线程操作的变量比如commitIndex 虽然是 volatile修饰了 但是是不是仍然存在线程安全问题可能被一个旧的更小的值覆盖掉?而这里的赋值有很多先查询后写入的过程,那如果这里有问题,我们继续推断一下,是不是所有多线程操作的变量都有可能出现更新丢失?
你最好将这块代码所在的 类#方法 说明白啊;
DefaultNode#handlerClientRequest() 方法