多进程调用共享资源

来源:互联网 发布:淘宝哎呦喂被挤爆了 编辑:程序博客网 时间:2024/06/13 15:04

本文主要参考Lamport算法,是对多进程调用共享资源算法的一个具体实现.业务场景为分布式中,使用dubbo调用后台某个服务,该服务部署有多个,服务中有对hdfs写的操作,要知道hdfs每次只支持一个客户端去写,所以这就是个多进程互斥访问共有资源的问题.下面是主要实现代码,具体业务可根据使用场景做调整:

public class WriteHDFS {    //本地用一个LinkedHashMap做时间戳存储    private static TreeMap<Long, String> queue = new TreeMap<Long, String>();    //每个服务初始化序号为0    private static long num = 0;    //最长心跳间隔    private static int MAX_TIME = 10000;    private static Date time1 = null;    private static Date time2 = null;    static Consumer statToHdfs = null;    public static void WriteHdfs(StatService statService, UserService userService) throws Exception {        //服务所在主机地址        String local = InetAddress.getLocalHost().getHostAddress();        InetAddress ip = InetAddress.getByName("255.255.255.255");        DatagramSocket sendDs = new DatagramSocket();        //将本地序号,ip封装后广播发送        HashMap<Long, String> sendMap = new HashMap<Long, String>();        /**         * 接收广播线程,更新序号         */        new Thread(new Runnable(){            @Override            public void run() {                //接收广播,将序号更新                DatagramSocket recvDs = null;                try {                    recvDs = new DatagramSocket(8888);                    byte[] buf = new byte[1024];                    DatagramPacket recvDp = new DatagramPacket(buf, buf.length);                    recvDs.receive(recvDp);                    String revStr = recvDp.getData().toString();                    JSONObject data = JSONObject.parseObject(revStr);                    if (data.containsKey("startData") || data.containsKey("endData")) {                        @SuppressWarnings("unchecked")                        HashMap<Integer, String> revMap = (HashMap<Integer, String>) data.get("startData");                        //遍历revMap,并放入本地队列                        for(Integer key:revMap.keySet()) {                            if (num <= key)                                num = key;                        }                    }                } catch (Exception e) {                    e.printStackTrace();                } finally {                    recvDs.close();                }            }        }).start();        /**         * 发送广播线程,更新队列         */        new Thread(new Runnable(){            @Override            public void run() {                //DatagramSocket sendDs = null;                //当要获取资源时,序号自增1,并广播通知其他服务                try {                    num++;                    sendMap.put(num, local);                    JSONObject startObj = new JSONObject();                    startObj.put("startData", sendMap);                    String startStr = startObj.toJSONString();                    DatagramPacket sendDp = new DatagramPacket(startStr.getBytes(),startStr.getBytes().length, ip, 8888);                    sendDs.send(sendDp);                } catch (Exception e) {                    e.printStackTrace();                }            }        }).start();        /**         * 接收广播,更新队列判断是否可以获取资源         */        new Thread(new Runnable() {            @Override            public void run() {                //接收广播,并比较key-value,直到获取资源                while(true) {                    //比较queue中最小key和此时num,以及主机ip,如果相同则表示可以获得资源                    if (queue.firstKey() == num && queue.get(queue.firstKey()) == local) {                        // 开启将数据周期写入Hdfs线程                        //此处为写hdfs业务逻辑,已省略xxxxxxx                        //queue移除首元素                        queue.remove(queue.firstKey());                        //资源释放,广播通知其他服务                        JSONObject endObj = new JSONObject();                        endObj.put("endData", sendMap);                        String endStr = endObj.toJSONString();                        DatagramPacket freeDp = new DatagramPacket(endStr.getBytes(),endStr.getBytes().length, ip, 8888);                        try {                            sendDs.send(freeDp);                        } catch (Exception e) {                            e.printStackTrace();                        }                        sendDs.close();                        break;                    }                    DatagramSocket ds = null;                    try {                        ds = new DatagramSocket(8888);                    } catch (Exception e) {                        e.printStackTrace();                    }                    byte[] bf = new byte[1024];                    DatagramPacket dp = new DatagramPacket(bf, bf.length);                    try {                        ds.receive(dp);                    } catch (Exception e) {                        e.printStackTrace();                    }                    String str = dp.getData().toString();                    JSONObject obj = JSONObject.parseObject(str);                    if (obj.containsKey("startData")) {                        @SuppressWarnings("unchecked")                        HashMap<Long, String> revMap = (HashMap<Long, String>) obj.get("startData");                        //遍历revMap,并放入本地队列                        for(Long key:revMap.keySet()) {                            if (!queue.containsKey(key)) {                                queue.put(key, revMap.get(key));                                //建立和正在使用资源服务的心跳连接,如果挂掉就从队列删除key-value                                Timer timer = new Timer();                                timer.scheduleAtFixedRate(new TimerTask() {                                    @Override                                    public void run() {                                        //向正在使用资源的服务发送心跳包                                        try {                                            @SuppressWarnings("resource")                                            DatagramSocket reqSocket = new DatagramSocket();                                            JSONObject reqObj = new JSONObject();                                            reqObj.put("requestData", local);                                            String reqStr = reqObj.toJSONString();                                            DatagramPacket reqDp = new DatagramPacket(reqStr.getBytes(),                                                    reqStr.getBytes().length, new InetSocketAddress(revMap.get(key), 8888));                                            reqSocket.send(reqDp);                                            time1 = new Date();                                        } catch (Exception e) {                                            e.printStackTrace();                                        }                                    }                                }, 1000, 3000);                                if(time1 != null && time2 != null && Math.abs(time1.getTime() - time2.getTime())/1000 > MAX_TIME) {                                    queue.remove(key);                                }                            }                        }                    }                    if (obj.containsKey("requestData")) {                        String reqHost = (String) obj.get("requestData");                        try {                            @SuppressWarnings("resource")                            DatagramSocket repSocket = new DatagramSocket();                            JSONObject repObj = new JSONObject();                            repObj.put("reponseData", local);                            String repStr = repObj.toJSONString();                            DatagramPacket repDp = new DatagramPacket(repStr.getBytes(),                                    repStr.getBytes().length, new InetSocketAddress(reqHost, 8888));                            repSocket.send(repDp);                        } catch (Exception e) {                            e.printStackTrace();                        }                    }                    if (obj.containsKey("reponseData")) {                        time2 = new Date();                    }                    if (obj.containsKey("endData")) {                        @SuppressWarnings("unchecked")                        HashMap<Long, String> revMap = (HashMap<Long, String>) obj.get("endData");                        //遍历revMap,从本地队列删除对应key-value                        for(Long key:revMap.keySet()) {                            if (queue.containsKey(key))                                queue.remove(key);                        }                    }                }            }        }).start();     }   }

需要用三个线程实现,主要原因是接受广播的方法是阻塞的.一个线程用来发送广播,一个用来接收广播,最后一个用来判断本地队列是否获取资源,如果为否则继续接收广播更新队列;队列用TreeMap顺序存储,如果获取资源的服务挂掉则可以通过心跳判断来更新本地队列;

原创粉丝点击