基于文件系统分布式锁原理

分布式锁:在一个公共的存储服务上打上一个标记,如Redis的setnx命令,是''先到先得''方式获得锁,ZooKeeper有点像下面的demo,比较大小的方式判决谁获得锁。

java 复制代码
package com.ldj.mybatisflex.demo;

import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * User: ldj
 * Date: 2025/1/12
 * Time: 1:50
 * Description: 基于文件系统制作的分布式锁demo
 */
public class LockDemo {

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

        //模拟文件存储系统
        List<String> files = new CopyOnWriteArrayList<>();
        List<Integer> hashCodes = new ArrayList<>();

        //使用3个线程模拟3台服务往文件存储系统写消息
        writeMsg(files, hashCodes);
        System.out.println("result:" + hashCodes.toString());

        //构建hashCode与IP的对映关系
        Map<String, String> map = new LinkedHashMap<>();
        for (int i = 0; i < hashCodes.size(); i++) {
            map.put(hashCodes.get(i).toString(), files.get(i).split(";")[0]);
        }
        System.out.println(map.toString());

        //排序获取最大数值
        Collections.sort(hashCodes);
        String key = hashCodes.get(hashCodes.size() - 1).toString();
        System.out.println("key: " + key);

        //比较3个消息code那个数字最大,最大的就是获得锁
        System.out.println("获得分布式锁的服务IP是: " + map.get(key));

        //模拟获得锁服务处理业务
        TimeUnit.SECONDS.sleep(3);

        //处理完成业务,通知文件存储系统清理消息文件(或者文件系统的定时任务自己处理也行)
        files.clear();
        System.out.println(files.toString());

        /*
         假设一个场景,1号服务获得锁,处理业务过程中挂了,会怎么样???
         响应超时
         用户重试请求
         需要服务协调器去注册中心,根据心跳机制找到健康的服务
         然后再重新获取分布式锁
         当然这个场景不需要分布式锁,直接让服务协调器负载均衡派发请求就好了
         */
    }

    private static void writeMsg(List<String> files, List<Integer> hashCodes) throws InterruptedException {
        //计数器,用于等待线程执行完毕!
        CountDownLatch count = new CountDownLatch(3);
        new Thread(() -> {
            files.add("192.168.208.1;" + UUID.randomUUID().toString().replaceAll("-", ""));
            count.countDown();
        }).start();

        new Thread(() -> {
            files.add("192.168.208.2;" + UUID.randomUUID().toString().replaceAll("-", ""));
            count.countDown();
        }).start();

        new Thread(() -> {
            files.add("192.168.208.3;" + UUID.randomUUID().toString().replaceAll("-", ""));
            count.countDown();
        }).start();

        //等待3个线程(服务器)往文件系统写消息
        count.await();
        System.out.println("3个模拟服务器往文件存储器完毕!");
        System.out.println(files.toString());

        //将消息字符串转为正整数字
        if (files.size() > 0) {
            for (String file : files) {
                hashCodes.add(Math.abs(file.hashCode()));
            }
        }

        //重复判单,确保每个数字不相等,如果相等再来一次
        HashSet<Integer> set = new HashSet<>(hashCodes);
        if (set.size() != hashCodes.size()) {
            files.clear();
            hashCodes.clear();
            writeMsg(files, hashCodes);
        }
    }
}
相关推荐
谢亮_vipxieliang几秒前
Spring Boot 3.x 从零开始——环境搭建与第一个 REST 项目
java·spring boot·后端
Wang's Blog9 分钟前
Java 项目部署之 Docker工具快速入门: Docker 架构拆解:镜像、容器、守护进程与 Registry
java·docker·架构
栗子~~10 分钟前
SpringCloud Gateway 基于 Nacos 实现动态路由
java·spring cloud·gateway
FYKJ_201017 分钟前
django个性化新闻推荐35173-计算机课程设计、毕业设计
java·spring boot·后端·python·架构·django·课程设计
计算机毕设定制辅导-无忧学长27 分钟前
《校园食堂在线订餐小程序的设计与实现》
java·vue.js·spring boot·微信小程序·uniapp·校园食堂在线订餐小程序
夜之眷属32 分钟前
服务启动即崩:InetAddress.getLocalHost() 抛 UnknownHostException 排查记
java·运维·后端·docker
IT研究室35 分钟前
最新计算机毕业设计选题推荐-基于spring boot的食品安全信息管理系统-网站-文档指导-Java-springboot
java·spring boot·课程设计
Sayai1 小时前
MCP Server 开发实战:Spring AI 把后端日志查询暴露给 AI Agent(7 条设计原则与踩坑实录)
java·人工智能·ai agent·spring ai·mcp
大牧师1 小时前
Mybatis 框架教程
java·数据库·mybatis·数据持久化·orm
SunnyDays10111 小时前
Java 合并 PDF 文件:完整合并、指定页面合并与流合并
java·开发语言·合并pdf