分布式锁纵观网络各种各样的帖子层出不穷,笔者查阅很多资料发现一个问题,有些文章只写原理并没有具体实现,有些文章虽然写了实现但是并不全面
借这个周末给大家做一个总结,代码拿来就可以用并且每一种实现都经过了测试没有bug。下面我们先从最简单的实现开始介绍:
简单的实现
package com.srr.lock; /** * @Description 分布式锁的接口 */ abstract public interface DistributedLock { /** * 获取锁 */ boolean lock(); /** * 解锁 */ void unlock(); abstract boolean readLock(); abstract boolean writeLock(); } package com.srr.lock; /** * 简单的zk分布式做实现策略 * 性能比较低会导致羊群效应 */ public abstract class SimplerZKLockStrategy implements DistributedLock{ /** * 模板方法,搭建的获取锁的框架,具体逻辑交于子类实现 * @throws Exception */ @Override public boolean lock() { //获取锁成功 if (tryLock()){ System.out.println(Thread.currentThread().getName()+"获取锁成功"); return true; }else{ //获取锁失败 //阻塞一直等待 waitLock(); //递归,再次获取锁 return lock(); } } /** * 尝试获取锁,子类实现 */ protected abstract boolean tryLock() ; /** * 等待获取锁,子类实现 */ protected abstract void waitLock(); /** * 解锁:删除key */ @Override public abstract void unlock(); } package com.srr.lock; import org.I0Itec.zkclient.IZkDataListener; import org.I0Itec.zkclient.ZkClient; import java.util.concurrent.CountDownLatch; /** * 分布式锁简单实现 */ public class SimpleZKLock extends SimplerZKLockStrategy{ private static final String PATH = "/lowPerformance_zklock"; private CountDownLatch countDownLatch = null; //zk地址和端口 public static final String ZK_ADDR = "192.168.32.129:2181"; //创建zk protected ZkClient zkClient = new ZkClient(ZK_ADDR); @Override protected boolean tryLock() { //如果不存在这个节点,则创建持久节点 try{ zkClient.createEphemeral(PATH, "lock"); return true; }catch (Exception e){ return false; } } @Override protected void waitLock() { IZkDataListener lIZkDataListener = new IZkDataListener() { @Override public void handleDataDeleted(String dataPath) throws Exception { if (null != countDownLatch){ countDownLatch.countDown(); } System.out.println("listen lock unlock"); } @Override public void handleDataChange(String dataPath, Object data) throws Exception { } }; //监听前一个节点的变化 zkClient.subscribeDataChanges(PATH, lIZkDataListener); if (zkClient.exists(PATH)) { countDownLatch = new CountDownLatch(1); try { countDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); } } zkClient.unsubscribeDataChanges(PATH, lIZkDataListener); } @Override public void unlock() { if (null != zkClient) { System.out.println("lock unclock"); zkClient.delete(PATH); } } @Override public boolean readLock() { return true; } @Override public boolean writeLock() { return true; } } package com.srr.lock; import redis.clients.jedis.Jedis; import java.util.concurrent.CountDownLatch; /** * 测试场景 * count从1加到4 * 使用简单的分布式锁在分布式环境下保证结果正确 */ public class T { volatile int count = 1; public void inc(){ for(int i = 0;i<3;i++){ try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } count++; System.out.println("count == "+count); } } public int getCount(){ return count; } public static void main(String[] args) throws InterruptedException { final T t = new T(); final Lock lock = new Lock(); final CountDownLatch countDownLatch = new CountDownLatch(5); for(int i = 0;i<5;i++){ new Thread(new Runnable() { @Override public void run() { DistributedLock distributedLock = new SimpleZKLock(); if(lock.lock(distributedLock)){ t.inc(); lock.unlock(distributedLock); countDownLatch.countDown(); } System.out.println("count == "+t.getCount()); } }).start(); } countDownLatch.await(); } }