分布式锁解决思路
分布式锁使用zk,在zk上创建一个临时节点(有效期),
使用临时节点作为锁,因为节点不允许重复。
如果能创建节点成功,生成订单号,如果创建节点失败,等待。
临时节点zk关闭,释放锁,其他节点就可以重新生成订单号。
小案例
依赖
<dependency> <groupId>com.101tec</groupId> <artifactId>zkclient</artifactId> <version>0.10</version> </dependency>
OrderNumber生成订单
public class OrderNumber {
private static Integer number=0;
//生成订单号
public String getNumber(){
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
++number;
return sdf.format(new Date())+" "+number;
}
}
OrderService打印订单号
public class OrderService implements Runnable{
private static OrderNumber orderNumber=new OrderNumber();
private Lock lock=new ZkLockImpl();
//生成订单
public void getOrderNumber(){
//获取锁
lock.getLock();
//生成订单号
System.out.println("订单号生成成功:"+orderNumber.getNumber());
//释放锁
lock.unLock();
}
@Override
public void run() {
getOrderNumber();
}
public static void main(String[] args) {
for (int i=1;i<=100;i++){
new Thread(new OrderService()).start();
}
}
}
Lock文接口
public interface Lock { //获取锁 public void getLock(); //释放锁 public void unLock(); }
ZookeeperLock实现
public abstract class ZookeeperLock implements Lock{ /** * 连接地址 */ private static final String ZK_ADDRESS="0.0.0.0:2181"; protected ZkClient zkClient=new ZkClient(ZK_ADDRESS); /** * 每一个进程在创建节点时,实际上就是获得了一把锁 * 如果在获取锁是发现返回值为true,代表当前没有锁,我可以使用 * 如果返回值为false,代表锁正在被占用,那么我只能等待 * */ @Override public void getLock() { //获取一把锁 if (tryLock()){ System.out.println("获取到锁资源"); }else{ //else代表锁正在被占用,请等待 waitLock(); //递归,再次获取锁 getLock(); } } @Override public void unLock() { //非等于空代表创建了订单号 if (zkClient!=null){ //关闭会话,删除节点 zkClient.close(); } } //获取锁资源 public abstract boolean tryLock(); //等待 public abstract void waitLock(); }
ZklockImpl实现
public class ZkLockImpl extends ZookeeperLock{ private CountDownLatch countDownLatch = null; @Override public boolean tryLock() { try { //创建临时节点 zkClient.createEphemeral("/zkTemp"); return true; }catch (Exception ex){ return false; } } @Override public void waitLock() { //监听节点是否被删除了 IZkDataListener iZkDataListener=new IZkDataListener() { @Override public void handleDataChange(String s, Object o) throws Exception { } @Override public void handleDataDeleted(String s) throws Exception { if(countDownLatch!=null){ //释放掉 countDownLatch.countDown(); } } }; //如果已经存在zkTemp节点,就等待 if(zkClient.exists("/zkTemp")){ countDownLatch=new CountDownLatch(1); System.out.println("订单号重复,请等待================================="); try { countDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); } } } }