分布式锁:在一个公共的存储服务上打上一个标记,如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);
}
}
}