github源码下载
一.分布式锁的几种实现方式和对比
实现思路 | 优点 | 缺点 | |
---|---|---|---|
利用MySQL数据库实现 | 利用数据库自身提供的锁 要求数据库支持行级锁 |
实现简单,稳定可靠 | 性能差,无法适应高并发场景 容易出现死锁的的情况 无法优雅的实现阻塞式锁 |
利用缓存(redis)的实现方案 | 基于redis的setnx命令实现 并通过lua脚本保证解锁时对缓存操作序列的原子性 |
性能好 | 实现相对复杂 又出现死锁的可能性 无法优雅的实现阻塞式锁 |
利用zookeeper的实现方案 | 基于zk节点特性以及watch机制实现 | 性能好,稳定可靠性,能较好的实现阻塞式锁 | 实现相对复杂 |
定义一个接口:
package com.roger.lock;
import java.util.concurrent.TimeUnit;
public interface DistributeLock {
void lock(String lockKey,String lockValue);
boolean tryLock(String lockKey,String lockValue);
boolean tryLock(String lockKey,String lockValue,long time, TimeUnit timeUnit);
boolean unLock(String lockKey,String lockValue);
}
二.分布式锁的具体实施方案
(1)利用MySQL数据库实现
实现思路:根据数据库表的主键唯一性特点,实现分布式锁,只要当insert成功后,才能获取到锁
package com.roger.lock.impl;
import com.roger.entity.DbDistriLock;
import com.roger.lock.DistributeLock;
import com.roger.mapper.DistributeLockMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
@Service("dbLock")
public class DbLock implements DistributeLock {
@Autowired
private DistributeLockMapper distributeLockMapper;
@Override
public void lock(String lockKey, String lockValue) {
if(!tryLock(lockKey,lockValue)){
//无法优雅的阻塞自己 -- 线程沉睡500ms
waitForLock();
//再次去尝试获取锁,直到获取成功
lock(lockKey,lockValue);
}
}
private void waitForLock() {
try {
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) {
}
}
@Override
public boolean tryLock(String lockKey, String lockValue) {
DbDistriLock dbDistriLock = new DbDistriLock();
dbDistriLock.setId(lockKey);
dbDistriLock.setDistributeLockName(lockValue);
try {
distributeLockMapper.insertDistributeLock(dbDistriLock);
}catch (Exception e){
return false;
}
return true;
}
@Override
public boolean tryLock(String lockKey, String lockValue, long time, TimeUnit timeUnit) {
if(tryLock(lockKey,lockValue)){
return true;
}
if(time <= 0){
return false;
}
long nanoTimes = tim