我正在为分布式系统项目实现Raft Consensus Algorithm。简而言之,有三种状态:
我不会告诉你每个州的具体情况,但是追随者可以成为候选人,候选人可以成为领导者。另外,外面的人可以再次成为候选人或领导者。在每种状态期间,服务器将执行不同的任务。
所以我开始考虑如何实现这种“状态改变”方面,这就是结果:
public abstract class ServerState implements Runnable {
protected Random timeoutGenerator;
public ServerState()
{
timeoutGenerator = new Random();
}
@Override
public abstract void run();
public abstract ServerState timeout();
public abstract ServerState taskCompleted() throws UnexpectedStateException;
public abstract long generateTimeout();
}
public class Follower extends ServerState{
@Override
public void run() {
System.out.println("Hello world! I'm a follower!");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {}
}
@Override
public ServerState timeout() {
return new Candidate();
}
@Override
public ServerState taskCompleted() throws UnexpectedStateException{
throw new UnexpectedStateException();
}
@Override
public long generateTimeout() {
return timeoutGenerator.nextInt(490)+10;
}
}
我不会发布相对于候选人和领导者的代码,因为他们与追随者非常相似。最有趣的部分是Executor类:
public class Executor extends Thread{
ExecutorService executor;
Future<?> future;
ServerState state;
public Executor ()
{
executor = Executors.newSingleThreadExecutor();
state = new Follower();
}
public synchronized void changeState(ServerState newState)
{
future.cancel(true);
executor.shutdownNow();
try {
executor.awaitTermination(5000, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}
executor = Executors.newSingleThreadExecutor();
state = newState;
future = executor.submit(state);
}
public void run()
{
future = executor.submit(state);
while(!Thread.currentThread().isInterrupted()) {
try {
future.get(state.generateTimeout(), TimeUnit.MILLISECONDS);//each server state has a different timeout
changeState(state.taskCompleted());
}
catch (CancellationException e){
System.out.println("Cancelled!");
}
catch (UnexpectedStateException | InterruptedException | ExecutionException e) {
e.printStackTrace();
executor.shutdownNow();
Thread.currentThread().interrupt();
}
catch (TimeoutException e) {
System.out.println("Timeout! Changing state");
changeState(state.timeout());//state.timeout return the new ServerState when the timeout elapse
}
}
}
}
正如我已经说过的,其他人可以更改服务器的实际状态,将其切换为Follower(事实上调用changeState(new Follower())
)。
现在,我问你一些问题:
changeState
方法内进行的,这是synchronized
,所以它应该是线程安全的,但我想要你的意见反正!有一个方面我不明白:这是执行的日志:
你好世界!我是追随者! 超时!改变状态 你好,世界!我是候选人! 超时!改变状态 你好,世界!我是候选人! 超时!改变状态 你好,世界!我是候选人! 超时!改变状态 你好,世界!我是候选人! 外部变化! 取消! 取消! 取消! 取消! 取消! 取消! 你好,世界!我是追随者! 依此类推......
(抱歉布局,我不知道为什么Stack Overflow只能在一行中写出来)
为什么消息Cancelled!
仅出现在EXTERNAL CHANGE
事件的位置?任何时候changeState()
被称为指令future.cancel(true)
,所以每次执行时CancellationException
都应该被提升!
实际发生了什么?我担心有些事我对未来不了解......