更改服务器状态:我做得对吗?

时间:2015-02-17 18:38:29

标签: java multithreading future

我正在为分布式系统项目实现Raft Consensus Algorithm。简而言之,有三种状态:

  1. 从动
  2. 候选
  3. 利达
  4. 我不会告诉你每个州的具体情况,但是追随者可以成为候选人,候选人可以成为领导者。另外,外面的人可以再次成为候选人或领导者。在每种状态期间,服务器将执行不同的任务。

    所以我开始考虑如何实现这种“状态改变”方面,这就是结果:

    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()))。

    现在,我问你一些问题:

    1. 您是否有更好的想法来提高此代码的质量(代码可读性)?
    2. 你认为它是线程安全的吗?我实现了这个解决方案,以便如果服务器的状态发生变化是在changeState方法内进行的,这是synchronized,所以它应该是线程安全的,但我想要你的意见反正!
    3. 有一个方面我不明白:这是执行的日志:

      你好世界!我是追随者! 超时!改变状态 你好,世界!我是候选人! 超时!改变状态 你好,世界!我是候选人! 超时!改变状态 你好,世界!我是候选人! 超时!改变状态 你好,世界!我是候选人! 外部变化! 取消! 取消! 取消! 取消! 取消! 取消! 你好,世界!我是追随者! 依此类推......

    4. (抱歉布局,我不知道为什么Stack Overflow只能在一行中写出来)

      为什么消息Cancelled!仅出现在EXTERNAL CHANGE事件的位置?任何时候changeState()被称为指令future.cancel(true),所以每次执行时CancellationException都应该被提升!

      实际发生了什么?我担心有些事我对未来不了解......

0 个答案:

没有答案