Zookeeper实现可重入分布式锁

原理见快速理解Zookeeper实现分布锁的原理及代码实现

 

抽象的OrderService接口:

public interface OrderService {
    void createOrder();
}

订单号生成类(模拟公共资源ps:需要用锁的地方):

import java.text.SimpleDateFormat;
import java.util.Date;
 
public class OrderCodeGenerator {
    private static int i = 0;
 
	public String getOrderCode() {
		Date now = new Date();
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss-");
		return sdf.format(now) + ++i;
	}
 
}

MyZkSerializer 继承了ZkSerializer:

 
import java.io.UnsupportedEncodingException;
 
import org.I0Itec.zkclient.exception.ZkMarshallingError;
import org.I0Itec.zkclient.serialize.ZkSerializer;
 
public class MyZkSerializer implements ZkSerializer {
 
	@Override
	public Object deserialize(byte[] bytes) throws ZkMarshallingError {
		try {
			return new String(bytes, "UTF-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
			throw new ZkMarshallingError(e);
		}
	}
 
	@Override
	public byte[] serialize(Object obj) throws ZkMarshallingError {
		try {
			return String.valueOf(obj).getBytes("UTF-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
			throw new ZkMarshallingError(e);
		}
	}
 
}

自己实现的可重入锁ZkReentrantLock:

import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
 
import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;

/**
 * 分布式可重入锁
 */
public class ZkReentrantLock implements Lock {
 
	private ZkClient client;

	//可提取为配置中,
	private static final String LOCK_PATH = "/REENT_LOCK";
 
	private String currentPath;
 
	private String beforePath;
 
	// 线程获取锁的次数
	private static volatile int state;
	// 当前获取锁的线程
	private static volatile Thread thread;
	
	public ZkReentrantLock() {
		super();
		client = new ZkClient("10.200.111.102:2181");
		client.setZkSerializer(new MyZkSerializer());
 
		if (!client.exists(LOCK_PATH)) {
			try {
				client.createPersistent(LOCK_PATH);
			} catch (Exception e) {
			}
		}
 
	}
 
	@Override
	public boolean tryLock() {
		return tryLock(1);
	}
 
	public boolean tryLock(int acquires) {
		// 获取当前线程
		final Thread currntThread = Thread.currentThread();
		// 获取当前锁的次数
		int state = getState();
 
		// state == 0 表示没有线程获取锁 进来的线程肯定能获取锁
		if (state == 0) {
			if (compareAndSetState(0, acquires, currntThread)) {
				return true;
			}
 
			// state != 0 表示线程被获取了 判断是否是当前线程 如果是则 state+1 ,否则返回false
		} else if (currntThread == getThread()) {
			int nextS = getState() + acquires;
 
			if (nextS < 0)
				throw new Error("Maximum lock count exceeded");
			// 这里不需要cas 原因不解释
			setState(nextS);
			System.out.println(Thread.currentThread().getName() + ":获取重入锁成功,当前获取锁次数: " + getState());
			return true;
		}
 
		// 获取锁的不是当前线程
		return false;
	}
 
	public boolean compareAndSetState(int expect, int update, Thread t) {
 
		if (this.currentPath == null) {
			currentPath = this.client.createEphemeralSequential(LOCK_PATH + "/", "1");
		}
 
		// 获取所有节点
		List<String> children = this.client.getChildren(LOCK_PATH);
 
		// 排序
		Collections.sort(children);
 
		// 判断当前节点是否为最小节点
		if (getState() == expect && currentPath.equals(LOCK_PATH + "/" + children.get(0))) {
			setState(update);
			thread = t;
			System.out.println(Thread.currentThread().getName() + ":获取锁成功,当前获取锁次数: " + getState());
			return true;
		}
 
		// 取得前一个
		// 得到字节的索引号
		int curIndex = children.indexOf(currentPath.substring(LOCK_PATH.length() + 1));
		beforePath = LOCK_PATH + "/" + children.get(curIndex - 1);
 
		return false;
	}
 
	public final boolean tryRelease(int releases) {
		// 可以判断是否自己获得锁 自己获得锁才能删除
		final Thread currentThread = Thread.currentThread();
		// 获取锁的不是当前线程
		if (currentThread != getThread()) {
			// throw new IllegalMonitorStateException();
			return false;
		}
 
		// 释放锁的次数
		int nextS = getState() - releases;
		boolean free = false;
		if (nextS == 0) {
			free = true;
			setThread(null);
			// 删除zk节点
			client.delete(currentPath);
			System.out.println(Thread.currentThread().getName() + ": 所有锁释放成功:删除zk节点...");
		}
 
		setState(nextS);
 
		if (!free)
			System.out.println(Thread.currentThread().getName() + ": 释放重入锁成功: 剩余锁次数:" + getState());
 
		return free;
	}
 
	@Override
	public void lock() {
		if (!tryLock()) {
			// 没有获得锁,阻塞自己
			waitForLock();
			// 再次尝试加锁
			lock();
		}
	}
 
	private void waitForLock() {
		CountDownLatch cdl = new CountDownLatch(1);
 
		IZkDataListener listener = new IZkDataListener() {
 
			@Override
			public void handleDataChange(String arg0, Object arg1) throws Exception {
 
			}
 
			@Override
			public void handleDataDeleted(String arg0) throws Exception {
				System.out.println("节点被删除了,开始抢锁...");
				cdl.countDown();
			}
 
		};
		// 完成watcher注册
		this.client.subscribeDataChanges(beforePath, listener);
 
		// 阻塞自己
		if (this.client.exists(beforePath)) {
			try {
				cdl.await();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
 
		// 取消注册
		this.client.unsubscribeDataChanges(beforePath, listener);
	}
 
	@Override
	public void unlock() {
		// 可以判断是否自己获得锁 自己获得锁才能删除
		// client.delete(currentPath);
		tryRelease(1);
 
	}
 
	public static int getState() {
		return state;
	}
 
	public static void setState(int state) {
		ZkReentrantLock.state = state;
	}
 
	public static Thread getThread() {
		return thread;
	}
 
	public static void setThread(Thread thread) {
		ZkReentrantLock.thread = thread;
	}
 
	@Override
	public void lockInterruptibly() throws InterruptedException {
	}
 
	@Override
	public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
		// TODO Auto-generated method stub
		return false;
	}
 
	@Override
	public Condition newCondition() {
		// TODO Auto-generated method stub
		return null;
	}
 
}

OrderServiceImplWithZkDis 实现了 OrderServiceI接口,并且测试方法也写在了里面:

 
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.locks.Lock;

/**
 * 业务实现,需要加锁的地方
 */
public class OrderServiceImplWithZkDis implements OrderService {
 
	private static OrderCodeGenerator org = new OrderCodeGenerator();
 
	//private Lock lock = new ZookeeperDisLock("/LOCK_TEST");
 
	private Lock lock = new ZkReentrantLock();
 
	@Override
	public void createOrder() {
		String orderCode = null;
 
		try {
			lock.lock();
 
			orderCode = org.getOrderCode();
			TestReLock();
 
			System.out.println(Thread.currentThread().getName() + "生成订单:" + orderCode);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
 
	}
 
	public void TestReLock() {
		lock.lock();
		System.out.println(Thread.currentThread().getName() + "测试重入锁成功...");
		lock.unlock();
 
	}
 
	public static void main(String[] args) {
		int num = 20;
		CyclicBarrier cyclicBarrier = new CyclicBarrier(num);
 
		for (int i = 0; i < num; i++) {
			new Thread(new Runnable() {
 
				@Override
				public void run() {
					OrderService orderService = new OrderServiceImplWithZkDis();
					System.out.println(Thread.currentThread().getName() + ": 我准备好了");
 
					try {
						cyclicBarrier.await();
					} catch (Exception e) {
						e.printStackTrace();
					}
 
					orderService.createOrder();
				}
			}).start();
		}
 
	}
 
}

 测试结果:

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值