一,定义锁接口
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
public interface Locker {
/**
* 锁
*/
void lock(String key, Runnable runnable);
/**
* 锁定超时
*/
void lock(String key, Runnable runnable, long time, TimeUnit unit);
/**
* 锁
*/
<T> T lock(String key, Supplier<T> supplier);
/**
* 锁定超时
*/
<T> T lock(String key, Supplier<T> supplier, long time, TimeUnit unit);
}
二,定义JDK锁
依赖jar包
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.1-jre</version>
</dependency>
import com.google.common.base.MoreObjects;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Supplier;
@Component("defaultLocker")
public class DefaultLocker implements Locker {
private static final Map<String, Lock> LOCKERS = new ConcurrentHashMap<>();
public Lock get(String key) {
Lock lock = LOCKERS.get(key);
if (Objects.nonNull(lock)) {
return lock;
}
ReentrantLock n = new ReentrantLock();
// 这里必须使用putIfAbsent,即原来没有才放入,以保证不会出现锁丢失
lock = LOCKERS.putIfAbsent(key, n);
// 如果原来有(可能是另一个线程放入的),就仍然返回原来有的,否则才返回自己创建的
return MoreObjects.firstNonNull(lock, n);
}
@Override
public void lock(String key, Runnable runnable) {
Lock lock = get(key);
try {
if (lock.tryLock()) {
runnable.run();
return;
}
throw new RuntimeException();//此处自定义抛出自定义异常
} finally {
lock.unlock();
}
}
@Override
public void lock(String key, Runnable runnable, long time, TimeUnit unit) {
Lock lock = get(key);
try {
if (lock.tryLock(time, unit)) {
runnable.run();
return;
}
throw new RuntimeException();
} catch (InterruptedException ignore) {
} finally {
lock.unlock();
}
}
@Override
public <T> T lock(String key, Supplier<T> supplier) {
Lock lock = get(key);
try {
if (lock.tryLock()) {
return supplier.get();
}
throw new RuntimeException();
} finally {
lock.unlock();
}
}
@Override
public <T> T lock(String key, Supplier<T> supplier, long time, TimeUnit unit) {
Lock lock = get(key);
try {
if (lock.tryLock(time, unit)) {
return supplier.get();
}
throw new RuntimeException();
} catch (InterruptedException e) {
throw new RuntimeException();
} finally {
lock.unlock();
}
}
}
二, 定义redis锁
依赖jar
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.13.6</version>
<exclusions>
<exclusion>
<artifactId>guava</artifactId>
<groupId>com.google.guava</groupId>
</exclusion>
</exclusions>
</dependency>
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
@Component("redisLocker")
public class RedisLocker implements Locker {
private final RedissonClient redissonClient;
public RedisLocker(RedissonClient redissonClient) {
this.redissonClient = redissonClient;
}
@Override
public void lock(String key, Runnable runnable) {
RLock lock = redissonClient.getLock(key);
try {
if (lock.tryLock()) {
runnable.run();
return;
}
throw new RuntimeException();
} finally {
if (lock.isLocked() && lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
@Override
public void lock(String key, Runnable runnable, long time, TimeUnit unit) {
RLock lock = redissonClient.getLock(key);
try {
if (lock.tryLock(time, unit)) {
runnable.run();
return;
}
throw new RuntimeException();
} catch (InterruptedException ignore) {
} finally {
if (lock.isLocked() && lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
@Override
public <T> T lock(String key, Supplier<T> supplier) {
RLock lock = redissonClient.getLock(key);
try {
if (lock.tryLock()) {
return supplier.get();
}
throw new RuntimeException();
} finally {
if (lock.isLocked() && lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
@Override
public <T> T lock(String key, Supplier<T> supplier, long time, TimeUnit unit) {
RLock lock = redissonClient.getLock(key);
try {
if (lock.tryLock(time, unit)) {
return supplier.get();
}
throw new RuntimeException();
} catch (InterruptedException e) {
throw new RuntimeException();
} finally {
if (lock.isLocked() && lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
}
三,定义锁实例
import org.springframework.stereotype.Component;
import java.util.function.Supplier;
@Component
public class EmployeeLocker {
private static final String LOCK_KEY_EMPLOYEE_ID = "{lk:employee:id:}%s";
private static final String LOCK_KEY_EMPLOYEE_ACCOUNT = "{lk:employee:account:}%s";
//这里根据情况使用redis锁或者jdk锁
@Autowired
@Qualifier(value = "redisLocker")
private Locker locker;
/**
* 锁ID
*/
public <T> T id(String id, Supplier<T> supplier) {
return locker.lock(getKey(id, LOCK_KEY_EMPLOYEE_ID), supplier);
}
/**
* 锁ID
*/
public void id(String id, Runnable runnable) {
locker.lock(getKey(id, LOCK_KEY_EMPLOYEE_ID), runnable);
}
/**
* 锁账户
*/
public <T> T account(String account, Supplier<T> supplier) {
return locker.lock(getKey(account, LOCK_KEY_EMPLOYEE_ACCOUNT), supplier);
}
/**
* 锁账号
*/
public void account(String account, Runnable runnable) {
locker.lock(getKey(account, LOCK_KEY_EMPLOYEE_ACCOUNT), runnable);
}
private String getKey(String id, String key) {
return String.format(key, id);
}
四,使用
@Autowired
private EmployeeLocker employeeLocker;
public void update(EmployeeCreateVO vo) {
employeeLocker.id(vo.getId(), () -> {
//业务逻辑处理
});
}