Paxos算法的java实现demo(只是为了简单的测试)

Paxos 的概念我就不在这里啰嗦了,网上有很多优秀的博客,下面是我推荐的一个写的比较好的

https://www.cnblogs.com/linbingdong/p/6253479.html 

我们直接上代码吧,代码里面都有注释

先看一下项目结构图

 

Acceptor类
package com.paxos;

import java.util.Map;

/**
 * @author jiezhou
 * @CalssName: Acceptor
 * @Package com.paxos
 * @Description: 接受者
 * @date 2020/6/24/16:08
 */
public class Acceptor {
    /**
     *  接受者的id(唯一标识)
     */
    int id;

    /**
     *  提案Map类型,key 为提案编号,value提案值
     */
    private Map<Integer,String> proporsal;

    /**
     *  接收过的最大提案编号N
     */
    int resN;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public Map<Integer, String> getProporsal() {
        return proporsal;
    }

    public void setProporsal(Map<Integer, String> proporsal) {
        this.proporsal = proporsal;
    }

    public int getResN() {
        return resN;
    }

    public void setResN(int resN) {
        this.resN = resN;
    }



    /**
     * @param proposerN 提案编号
     *
     */
    public Map<Integer, String> prepareReq(int proposerN ){
        if(proposerN<this.resN){ //不响应
            System.out.println("proposerN:"+proposerN+",this.resN"+resN);
            return null;
        }else{
            this.resN=proposerN;
            //响应pok
            return this.proporsal;
        }
    }

    /**
     *  第二阶段的 accept请求
     */
    public String acceptReq(Map<Integer,String> map){
        for (Map.Entry<Integer, String> entry : map.entrySet()) {
            if (entry.getKey()>=this.resN){
                this.setProporsal(map);
                return "aok";
            }
        }
        return "no";
    }
}

 

 

Common类
package com.paxos;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author jiezhou
 * @CalssName: common
 * @Package com.paxos
 * @Description: 公有的数据类
 * @date 2020/6/24/16:18
 */
public class Common {
    /**
     * 提交者数量
     */
    public static final int PROPOSER_COUNT = 2;


    /**
     *  接受者数量
     */
    public static final int ACCEPTOR_COUNT = 3;

    /**
     * 全局提案编号(初始值为1)
     */
    public static AtomicInteger proposerN=new AtomicInteger(0);
}

 

Proposer类
package com.paxos;

import java.util.Map;

/**
 * @author jiezhou
 * @CalssName: Proposer
 * @Package com.paxos
 * @Description: 提议者
 * @date 2020/6/24/16:08
 */
public class Proposer {
    /**
     * 提议者id(唯一标识)
     */
    private int id;

    /**
     *  提案Map类型,key 为提案编号,value提案值
     */
    private Map<Integer,String> proporsal;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public Map<Integer, String> getProporsal() {
        return proporsal;
    }

    public void setProporsal(Map<Integer, String> proporsal) {
        this.proporsal = proporsal;
    }


}

 

RandomUtils类
package com.paxos;

import java.util.Random;

/**
 * @author jiezhou
 * @CalssName: RandomUtils
 * @Package com.paxos
 * @Description: 随机数(模拟由于网络通信挂掉的提交者或者接受者的id)
 * @date 2020/6/24/16:22
 */
public class RandomUtils {

    public static int randomAcceptorId(){
        Random random = new Random();
        int id = random.nextInt(Common.ACCEPTOR_COUNT)+1;
        System.out.println(id);
        return id;
    }
    public static int randomProposerId(){
        Random random = new Random();
        int id = random.nextInt(Common.PROPOSER_COUNT)+1;
//        System.out.println(id);
        return id;
    }

   /* public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            randomProposerId();
        }

    }*/
}

 

Test类
package com.paxos;

import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author jiezhou
 * @CalssName: Test
 * @Package com.paxos
 * @Description: 测试
 * @date 2020/6/24/16:15
 */
public class Test {

    private static ExecutorService executorService = Executors.newFixedThreadPool(10);
    //接受者集合
    private static List<Acceptor> acceptorList=new ArrayList<>();
    //提交者集合
    private static List<Proposer> proposerList=new ArrayList<>();
    /**
     * 初始化方法
     */
    public static void init(){
        //初始化接受者 acceptor
        for (int i = 1; i <= Common.ACCEPTOR_COUNT; i++) {
            Acceptor acceptor = new Acceptor();
            acceptor.setId(i);
            acceptor.setResN(0);
            acceptor.setProporsal(new HashMap<>());
            acceptorList.add(acceptor);
        }
        //初始化提交者proposer
        for (int i = 1; i <= Common.PROPOSER_COUNT; i++) {
            Proposer proposer = new Proposer();
            proposer.setId(i);
            proposer.setProporsal(new HashMap<>());
            proposerList.add(proposer);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        init();

        int id = RandomUtils.randomProposerId();//宕机id
        for (int i = 0; i < proposerList.size(); i++) {
            Proposer proposer = proposerList.get(i);
            if(id!=proposer.getId()){//使用Random来模拟网络通信阻塞(宕机)
                executorService.execute(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            guocheng(proposer);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                });
            }
        }

        Thread.sleep(4000);
        //宕机的机器重启了
        for (Proposer proposer1 : proposerList) {
            if(proposer1.getId()==id){//找到宕机的机器
                executorService.execute(new Runnable() {//模拟重启
                    @Override
                    public void run() {
                        try {
                            System.out.println("提交者id:"+id+"重启了");
                            guocheng(proposer1);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                });
            }
        }

    }


    public static void guocheng( Proposer proposer) throws InterruptedException {
        //1、生成提案
        // 先判断(学习)之前的接受者里面有没有接受之前提议者的提案,没有就自己生成一个提案
        //如果有接受者已经接受了之前提议者的提案,无论自己的提案编号大还是小,都得把自己的提案的value指定为之前的那个提案的value
        if(!chackAccept()){//没有接受过提案
            HashMap<Integer, String> map = new HashMap<>();
            map.put(Common.proposerN.incrementAndGet(),"提案"+proposer.getId());
            proposer.setProporsal(map);
        }else{
            //之前有接受者接受过提案,只能乖乖用之前的提案值(也就是Map的value使用之前的提案的)
            for (int i = 0; i < acceptorList.size(); i++) {
                Acceptor acceptor = acceptorList.get(i);
                Map<Integer, String> proporsal = acceptor.getProporsal();
                if(proporsal.size()!=0){
                    for (Map.Entry<Integer, String> entry : proporsal.entrySet()) {
                        Map<Integer, String> map = new HashMap<>();
                        map.put(Common.proposerN.incrementAndGet(),entry.getValue());
                        proposer.setProporsal(map);
                        break;
                    }
                    break;
                }
            }
        }

        Integer var1=0;//提案编号
        Map<Integer, String> proporsal = proposer.getProporsal();
        Set<Map.Entry<Integer, String>> entries = proporsal.entrySet();
        for (Map.Entry<Integer, String> entry : entries) {
            var1 = entry.getKey();
        }



        //2、prepare请求(这里是对所有的接受者进行请求)
        //统计 prepare请求  pok响应的个数
        AtomicInteger var2 =new AtomicInteger(0);
        Map<Integer, String> var3;
        String maxAcceptV;
        int maxAcceptN=0;
        Boolean flg=true;
        for (int i = 0; i < acceptorList.size(); i++) {
            Acceptor acceptor = acceptorList.get(i);
            var3 = acceptor.prepareReq(var1);
            if(var3!=null){
                var2.incrementAndGet();
                for (Map.Entry<Integer, String> var4 : var3.entrySet()) {
                    Integer key = var4.getKey();
                    if(flg){
                        maxAcceptN=key;
                        maxAcceptV=var4.getValue();
                        flg=false;
                    }
                    if(maxAcceptN<key){
                        maxAcceptN=key;
                        maxAcceptV=var4.getValue();
                    }
                }
            }
        }
        //判断是否收到超过一半响应(包括一半)
        //阶段2,accept请求
        AtomicInteger aokCount=new AtomicInteger(0);
        Boolean half = chackHalf(Common.ACCEPTOR_COUNT, var2.intValue());
        if(half){
            for (Acceptor acceptor : acceptorList) {
                String req = acceptor.acceptReq(proporsal);
                if("aok".equals(req)){
                    aokCount.incrementAndGet();
                }
            }
        }else{
            guocheng(proposer);
        }
        //如果过半,V被确定,不过半,重新发起Prepare请求
        Boolean var4 = chackHalf(Common.ACCEPTOR_COUNT, aokCount.intValue());
        if(var4){
            //输出一下每个acceptor的AcceptV
            for (Acceptor acceptor : acceptorList) {
                for (Map.Entry<Integer, String> entry : acceptor.getProporsal().entrySet()) {
                    System.out.println("接受者的id:"+acceptor.getId()+"最终acceptN :"+entry.getKey()+",最终acceptV:"+entry.getValue());
                }
            }
            return;//结束
        }else{
            guocheng(proposer);
        }

    }

    /**
     *  判断是否超过一半响应
     * @param total
     * @param var1
     * @return true 过半  false 不过半
     */
    public static Boolean chackHalf(int total,int var1){
        double var = total / 2;
        if(var>var1){
            return false;
        }else{return true;}
    }

    /**
     *
     * @return false 没有接收提案
     */
    public static Boolean chackAccept(){
        Boolean res=true;
        for (int i = 0; i < acceptorList.size(); i++) {
            Acceptor acceptor = acceptorList.get(i);
            Map<Integer, String> proporsal = acceptor.getProporsal();
            if(proporsal.size()==0){//之前没有接受过提案
                res=false;
                break;
            }
        }
        return res;
    }




}

 

 

增强版的,只需要吧Test类换掉就行,如下

package com.paxos;

import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author jiezhou
 * @CalssName: Test
 * @Package com.paxos
 * @Description: 测试
 * @date 2020/6/24/16:15
 */
public class Test {

    private static ExecutorService executorService = Executors.newFixedThreadPool(10);
    //接受者集合(全部)
    private static List<Acceptor> acceptorList=new ArrayList<>();
    //接受者集合(过半)
    private static List<Acceptor> acceptorListQuorum=new ArrayList<>();
    //提交者集合
    private static List<Proposer> proposerList=new ArrayList<>();
    private static Thread thread;
    private static Thread runnable;

    /**
     * 初始化方法
     */
    public static void init(){
        //初始化接受者 acceptor (全部)
//        for (int i = 1; i <= Common.ACCEPTOR_COUNT; i++) {
//            Acceptor acceptor = new Acceptor();
//            acceptor.setId(i);
//            acceptor.setResN(0);
//            acceptor.setProporsal(new HashMap<>());
//            acceptorList.add(acceptor);
//        }

        //初始化提交者proposer
        for (int i = 1; i <= Common.PROPOSER_COUNT; i++) {
            Proposer proposer = new Proposer();
            proposer.setId(i);
            proposer.setProporsal(new HashMap<>());
            proposerList.add(proposer);
        }


    }

    private static void randomAcceptorQuorum() {
        ArrayList<Acceptor> temp = new ArrayList<>();
        ArrayList<Integer> ids = new ArrayList<>();
        Random random = new Random();
        for (;;) {
            int id = random.nextInt(Common.ACCEPTOR_COUNT)+1;
            if(ids.contains(id)){
                continue;
            }
            double ceil = (Common.ACCEPTOR_COUNT / 2)+1;
            if(ids.size()==ceil){
                break;
            }

            if(acceptorListQuorum.size()==0){
                Acceptor acceptor = new Acceptor();
                acceptor.setId(id);
                acceptor.setResN(0);
                acceptor.setProporsal(new HashMap<>());
                temp.add(acceptor);
                ids.add(id);
            }else{
                Boolean f=false;
                for (Acceptor acceptor : acceptorListQuorum) {
                    if(id==acceptor.getId()){
                        temp.add(acceptor);
                        ids.add(id);
                        f=true;
                    }
                }
                if(!f){
                    Acceptor acceptor = new Acceptor();
                    acceptor.setId(id);
                    acceptor.setResN(0);
                    acceptor.setProporsal(new HashMap<>());
                    temp.add(acceptor);
                    ids.add(id);
                }
            }
        }
        acceptorListQuorum=temp;
    }

    public static void main(String[] args) throws InterruptedException {
        init();

        int id = RandomUtils.randomProposerId();//宕机id
        for (int i = 0; i < proposerList.size(); i++) {
            Proposer proposer = proposerList.get(i);
            if(id!=proposer.getId()){//使用Random来模拟网络通信阻塞(宕机)
                runnable = new Thread() {
                    @Override
                    public void run() {
                        try {
                            guocheng(proposer);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                };
                runnable.start();

            }
        }

        Thread.sleep(4000);
        //宕机的机器重启了
        for (Proposer proposer1 : proposerList) {
            if(proposer1.getId()==id){//找到宕机的机器
                thread = new Thread() {//模拟重启
                    @Override
                    public void run() {
                        try {
                            runnable.join();
                            System.out.println("提交者id:" + id + "重启了");
                            guocheng(proposer1);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                };
                thread.start();
            }
        }

    }


    public static void guocheng( Proposer proposer) throws InterruptedException {
        //1、生成提案
        // 先判断(学习)之前的接受者里面有没有接受之前提议者的提案,没有就自己生成一个提案
        //如果有接受者已经接受了之前提议者的提案,无论自己的提案编号大还是小,都得把自己的提案的value指定为之前的那个提案的value
        randomAcceptorQuorum();
        if(!chackAccept()){//没有接受过提案
            HashMap<Integer, String> map = new HashMap<>();
            map.put(Common.proposerN.incrementAndGet(),"提案"+proposer.getId());
            proposer.setProporsal(map);
        }else{
            //之前有接受者接受过提案,只能乖乖用之前的提案值(也就是Map的value使用之前的提案的)
            for (int i = 0; i < acceptorListQuorum.size(); i++) {
                Acceptor acceptor = acceptorListQuorum.get(i);
                Map<Integer, String> proporsal = acceptor.getProporsal();
                if(proporsal.size()!=0){
                    for (Map.Entry<Integer, String> entry : proporsal.entrySet()) {
                        Map<Integer, String> map = new HashMap<>();
                        map.put(Common.proposerN.incrementAndGet(),entry.getValue());
                        proposer.setProporsal(map);
                        break;
                    }
                    break;
                }
            }
        }

        Integer var1=0;//提案编号
        Map<Integer, String> proporsal = proposer.getProporsal();
        Set<Map.Entry<Integer, String>> entries = proporsal.entrySet();
        for (Map.Entry<Integer, String> entry : entries) {
            var1 = entry.getKey();
        }



        //2、prepare请求(这里是对半数以上的接受者进行请求)
        //统计 prepare请求  pok响应的个数
        randomAcceptorQuorum();
        AtomicInteger var2 =new AtomicInteger(0);
        Map<Integer, String> var3;
        String maxAcceptV;
        int maxAcceptN=0;
        Boolean flg=true;
        for (int i = 0; i < acceptorListQuorum.size(); i++) {
            Acceptor acceptor = acceptorListQuorum.get(i);
            var3 = acceptor.prepareReq(var1);
            if(var3!=null){
                var2.incrementAndGet();
                for (Map.Entry<Integer, String> var4 : var3.entrySet()) {
                    Integer key = var4.getKey();
                    if(flg){
                        maxAcceptN=key;
                        maxAcceptV=var4.getValue();
                        flg=false;
                    }
                    if(maxAcceptN<key){
                        maxAcceptN=key;
                        maxAcceptV=var4.getValue();
                    }
                }
            }
        }
        //判断是否收到超过一半响应(包括一半)
        //阶段2,accept请求
        randomAcceptorQuorum();
        AtomicInteger aokCount=new AtomicInteger(0);
        Boolean half = chackHalf(Common.ACCEPTOR_COUNT, var2.intValue());
        if(half){
            for (Acceptor acceptor : acceptorListQuorum) {
                String req = acceptor.acceptReq(proporsal);
                if("aok".equals(req)){
                    aokCount.incrementAndGet();
                }
            }
        }else{
            guocheng(proposer);
        }
        //如果过半,V被确定,不过半,重新发起Prepare请求
        Boolean var4 = chackHalf(Common.ACCEPTOR_COUNT, aokCount.intValue());
        if(var4){
            //输出一下每个acceptor的AcceptV
            for (Acceptor acceptor : acceptorListQuorum) {
                for (Map.Entry<Integer, String> entry : acceptor.getProporsal().entrySet()) {
                    System.out.println("接受者的id:"+acceptor.getId()+"最终acceptN :"+entry.getKey()+",最终acceptV:"+entry.getValue());
                }
            }
            return;//结束
        }else{
            guocheng(proposer);
        }

    }

    /**
     *  判断是否超过一半响应
     * @param total
     * @param var1
     * @return true 过半  false 不过半
     */
    public static Boolean chackHalf(int total,int var1){
        double var = total / 2.0;
        if(var>var1){
            return false;
        }else{return true;}
    }

    /**
     *
     * @return false 没有接收提案 true 有接受过提案
     */
    public static Boolean chackAccept(){
        Boolean res=false;
        for (int i = 0; i < acceptorListQuorum.size(); i++) {
            Acceptor acceptor = acceptorListQuorum.get(i);
            Map<Integer, String> proporsal = acceptor.getProporsal();
            if(proporsal.size()!=0){//之前有接受过提案
                return true;
            }
        }
        return res;
    }




}

 

运行结果(增强版的运行结果):

如有bug或者错误,欢迎大家评论,大家一起学习。完整代码:https://github.com/jcode95/Paxos-java-demo

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章