我在此谈谈自己对java锁(java.util.concurrent.locks)的理解以及分布式的环境下锁的处理。在大型项目高访问量高并发量是在所难免的,为了解决此类问题,我们需要用到锁。
首先,在单机的环境下线程竞争同一资源,需要获取一个同步锁,谁先得到谁就可以进入第二关获取分布式锁。通过Redisson的机制我们可以在不同机器的情况下同时竞争同一个key的锁,哪一台机器得到此锁就有处理的优先权。其他服务器就只能等待获取分布式锁(当然等待也会有超时,超时默认当作响应失败),处理完成后释放锁,其他线程就可以继续竞争该锁。
在实现的过程中要注意的地方对锁释放的处理,一般如果使用了锁在超时或程序报异常等情况下就需要释放下锁unlock();
最后附上一些核心关键性代码。
public class Lock implements ILock { private static final int PERIOD = 100; private static final HashMap<String, RlockThread> rLockTheads = new HashMap<>(); private static final HashMap<String, ReentrantLock> sMap = new HashMap<>(); private static final HashMap<String, Integer> sMapNum = new HashMap<>(); private static final HashMap<String, Object> sKey = new HashMap<>(); private RedissonClient redissonClient; private String key; private Lock(String key, RedissonHelper redissonHelper) { //初始化锁 this.key = key; redissonClient = redissonHelper.getClient(); } @Override public boolean require(long waitTime, long leaseTime, TimeUnit timeUnit) { num(1);//计数器 boolean r1 = false; try { ReentrantLock reentrantLock = sMap.get(key); r1 = reentrantLock.tryLock(waitTime, timeUnit); } catch (Exception e) { e.printStackTrace(); num(-1); return false; } if (!r1) { num(-1); return false; } RlockThread rlockThread = rLockTheads.get(key); if (rlockThread == null) { CountDownLatch countDownLatch = new CountDownLatch(1); rlockThread = new RlockThread(waitTime, leaseTime, timeUnit, countDownLatch); try { rlockThread.start(); countDownLatch.await(); } catch (Exception e) { e.printStackTrace(); unlockReentrantLock(); return false; } if (!rlockThread.isGotLock) { unlockReentrantLock(); return false; } rLockTheads.put(key, rlockThread); } return true; } private int num(int incr) { Object kk = sKey.get(key); if (kk == null) { synchronized (sKey) { kk = sKey.get(key); if (kk == null) { kk = new Object(); sKey.put(key, kk); } } } synchronized (kk) { int _num; Integer num = sMapNum.get(key); if (num == null) { _num = 0; } else { _num = num; } _num += incr; if (_num > 0) { sMapNum.put(key, _num); ReentrantLock lock = sMap.get(key); if (lock == null) { lock = new ReentrantLock(); sMap.put(key, lock); } } else { ReentrantLock locks = sMap.remove(key); System.out.println("r:"+locks); sMapNum.remove(key); sKey.remove(key); if (locks != null) { } RlockThread rlockThread = rLockTheads.remove(key); if (rlockThread != null) { rlockThread.unLock(); } } return _num; } } private void unlockReentrantLock() { ReentrantLock reentrantLock = sMap.get(key); num(-1); reentrantLock.unlock(); } @Override public void release() { unlockReentrantLock(); } public class RlockThread extends Thread { private long waitTime; private long leaseTime; private TimeUnit timeUnit; private CountDownLatch countDownLatch; private CountDownLatch callback; private boolean isGotLock = false; public RlockThread(long waitTime, long leaseTime, TimeUnit timeUnit, CountDownLatch countDownLatch) { this.waitTime = waitTime; this.leaseTime = leaseTime; this.timeUnit = timeUnit; this.countDownLatch = countDownLatch; } @Override public void run() { super.run(); RLock rLock = null; boolean r = false; try { rLock = redissonClient.getLock(key); long start = System.currentTimeMillis(); while (true) { Thread.sleep(PERIOD); r = rLock.tryLock(); if (r) { break; } long wai = timeUnit.toMillis(waitTime); if (System.currentTimeMillis() - start > wai) { break; } } } catch (Exception e) { e.printStackTrace(); countDownLatch.countDown(); return; } if (!r) { countDownLatch.countDown(); return; } isGotLock = true; callback = new CountDownLatch(1); countDownLatch.countDown(); try { callback.await(); } catch (InterruptedException e) { e.printStackTrace(); rLockTheads.remove(key); } if (rLock != null) { rLock.unlock(); } } public void unLock() { callback.countDown(); } } @Component public static class LockBuilder { @Autowired private RedissonHelper redissonHelper; public ILock build(String key) { return new Lock(key, redissonHelper); } } }