使用锁存在一个问题,在有限时间内释放,也可能被其他等待的线程获取锁,所以在锁内部仍然需要通过查询来判断是否已经被更新过;
获取锁和根据锁的获取结果回调函数
public class ZkDistributedLockTemplate implements DistributedLockTemplate { private static final org.slf4j.Logger log = LoggerFactory.getLogger(ZkDistributedLockTemplate.class); private CuratorFramework client; public ZkDistributedLockTemplate(CuratorFramework client) { this.client = client; } private boolean tryLock(ZkReentrantLock distributedReentrantLock,Long timeout) throws Exception { return distributedReentrantLock.tryLock(timeout, TimeUnit.MILLISECONDS); } public Object execute(String lockId, int timeout, Callback callback) { ZkReentrantLock distributedReentrantLock = null; boolean getLock=false; try { distributedReentrantLock = new ZkReentrantLock(client,lockId); if(tryLock(distributedReentrantLock,new Long(timeout))){ getLock=true; return callback.onGetLock(); }else{ return callback.onTimeout(); } }catch(InterruptedException ex){ log.error(ex.getMessage(), ex); Thread.currentThread().interrupt(); }catch (Exception e) { log.error(e.getMessage(), e); }finally { if(getLock){ distributedReentrantLock.unlock(); } } return null; } }
分布式锁的核心实现:
public class ZkReentrantLock implements DistributedReentrantLock { private static final org.slf4j.Logger log = LoggerFactory.getLogger(ZkReentrantLock.class); /** * 线程池 */ private static final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(10); /** * 所有PERSISTENT锁节点的根位置 */ public static final String ROOT_PATH = "/ROOT_LOCK/"; /** * 每次延迟清理PERSISTENT节点的时间 Unit:MILLISECONDS */ private long delayTimeForClean = 1000; /** * zk 共享锁实现 */ private InterProcessMutex interProcessMutex = null; /** * 锁的ID,对应zk一个PERSISTENT节点,下挂EPHEMERAL节点. */ private String path; /** * zk的客户端 */ private CuratorFramework client; public ZkReentrantLock(CuratorFramework client, String lockId) { init(client, lockId); } public void init(CuratorFramework client, String lockId) { this.client = client; this.path = ROOT_PATH + lockId; interProcessMutex = new InterProcessMutex(client, this.path); } @Override public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { try { return interProcessMutex.acquire(timeout, unit); } catch (InterruptedException e) { throw e; } catch (Exception e) { log.error(e.getMessage(),e); throw new RuntimeException(e.getMessage(),e); } } @Override public void unlock() { try { interProcessMutex.release(); } catch (Throwable e) { log.error(e.getMessage(), e); } finally { executorService.schedule(new Cleaner(client, path), delayTimeForClean, TimeUnit.MILLISECONDS); } } static class Cleaner implements Runnable { CuratorFramework client; String path; public Cleaner(CuratorFramework client, String path) { this.client = client; this.path = path; } public void run() { try { List list = client.getChildren().forPath(path); if (list == null || list.isEmpty()) { client.delete().forPath(path); } } catch (KeeperException.NoNodeException e1) { //nothing } catch (KeeperException.NotEmptyException e2) { //nothing } catch (Exception e) { log.error(e.getMessage(), e);//准备删除时,正好有线程创建锁 } } } private boolean isEmpty(List<String> list){ return list==null||list.isEmpty(); } }
测试代码:
@Test public void testTry() throws InterruptedException { RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3); CuratorFramework client = CuratorFrameworkFactory.newClient("192.168.2.6:2181", retryPolicy); client.start(); final ZkDistributedLockTemplate template=new ZkDistributedLockTemplate(client); int size=100; final CountDownLatch startCountDownLatch = new CountDownLatch(1); final CountDownLatch endDownLatch=new CountDownLatch(size); for (int i =0;i<size;i++){ new Thread() { public void run() { try { startCountDownLatch.await(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } final int sleepTime=ThreadLocalRandom.current().nextInt(5)*1000; template.execute("locktest",5000, new Callback() { public Object onGetLock() throws InterruptedException { System.out.println(Thread.currentThread().getName() + ":getLock"); Thread.currentThread().sleep(sleepTime); System.out.println(Thread.currentThread().getName() + ":sleeped:"+sleepTime); endDownLatch.countDown(); return null; } public Object onTimeout() throws InterruptedException { System.out.println(Thread.currentThread().getName() + ":timeout"); endDownLatch.countDown(); return null; } }); } }.start(); } startCountDownLatch.countDown(); endDownLatch.await(); }
预览结果,当锁释放后,线程信息全部置空,locktest变回叶子节点
具体参考:
https://github.com/yujiasun/Distributed-Kit