当前位置:网站首页>A simple (redisson based) distributed synchronization tool class encapsulation
A simple (redisson based) distributed synchronization tool class encapsulation
2022-04-23 19:26:00 【justry_ deng】
A simple ( be based on redisson Of ) Distributed synchronization tool class encapsulation
The background that
Some distributed synchronization logic does not need to act on the entire method , Just act on the specified business logic code block , Be similar to synchronized Code block . So there is the following simple encapsulation class .
preparation
Tips : In this synchronization tool class redis Distributed lock directly adopts redisson Realization .
First step : introduce redisson rely on
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.17.0</version>
</dependency>
The second step : To configure RedissonClient
Tips : The configuration here is based on monomer redis For example , For more details, please refer to redisson Official website .
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/** * RedissonConfig * * @author JustryDeng * @since 2022/3/25 10:33 */
@Slf4j
@Configuration
public class RedissonConfig {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private String port;
@Bean
public RedissonClient redissonClient() {
Config config = new Config();
String address = host + ":" + port;
log.info("redis address -> {}", address);
config.useSingleServer()
.setAddress("redis://" + address);
RedissonClient redissonClient = Redisson.create(config);
return redissonClient;
}
}
Tool class
Tool class interface
import lombok.Getter;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Function;
/** * redis Lock support * * @author JustryDeng * @since 2022/4/19 9:36 */
public interface RedisLockSupport {
/** * Execute synchronization logic * <br /> * This logic , Should be redis lock Ensure global synchronization * * @param function * Business logic block * @param param * Parameters * * @throws NotAcquiredRedisLockException obtain redis Failed to throw lock * @return Logical execution results */
<P, R> R exec(Function<P, R> function, P param) throws NotAcquiredRedisLockException;
/** * Execute synchronization logic * <br /> * This logic , Should be redis lock Ensure global synchronization * * @param function * Business logic block * @return Execution results * * @throws NotAcquiredRedisLockException obtain redis Failed to throw lock */
<R> R exec(NoArgFunction<R> function) throws NotAcquiredRedisLockException;
/** * Execute synchronization logic * <br /> * This logic , Should be redis lock Ensure global synchronization * * @param consumer * Business logic block * @param param * Parameters * * @throws NotAcquiredRedisLockException obtain redis Failed to throw lock */
<P> void voidExec(Consumer<P> consumer, P param) throws NotAcquiredRedisLockException;
/** * Execute synchronization logic * <br /> * This logic , Should be redis lock Ensure global synchronization * * @param consumer * Business logic block * @throws NotAcquiredRedisLockException obtain redis Failed to throw lock */
void voidExec(NoArgConsumer consumer) throws NotAcquiredRedisLockException;
/** * obtain redis lock Failure * * @author JustryDeng * @since 2022/4/19 10:44 */
@Getter
class NotAcquiredRedisLockException extends RuntimeException{
/** lock key */
private final String lockKey;
/** The maximum length of time waiting to acquire a lock */
private final long waitTime;
/** waitTime Time unit of */
private final TimeUnit timeUnit;
public NotAcquiredRedisLockException(String lockKey, long waitTime, TimeUnit timeUnit) {
super(String.format("lockKey=%s, waitTime=%d, timeUnit=%d", lockKey, waitTime, timeUnit));
this.lockKey = lockKey;
this.waitTime = waitTime;
this.timeUnit = timeUnit;
}
}
}
Default implementation of tool class interface
import lombok.Getter;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Function;
/** * redis Distributed locks are implemented by default * <p> * See... For an example {@link com.ideaaedi.heywebuy.srv.RedisLockSupportTest} * </p> * * @author JustryDeng * @since 2022/4/19 10:08 */
@Getter
public class DefaultRedisLockSupport implements RedisLockSupport {
/** default redisson client */
private static volatile RedissonClient defaultRedissonClient;
/** redisson client ( Priority over defaultRedissonClient, When redissonClient Not for null when , Use redissonClient) */
protected RedissonClient redissonClient;
/** lock key */
protected final String lockKey;
/** The maximum length of time waiting to acquire a lock */
protected long waitTime = 1L;
/** Maximum time to release the lock */
protected long leaseTime = 3L;
/** WaitTime and LeaseTime Time unit of */
protected TimeUnit unit = TimeUnit.SECONDS;
public DefaultRedisLockSupport(String lockKey) {
this.lockKey = lockKey;
}
public DefaultRedisLockSupport(RedissonClient redissonClient, String lockKey) {
this.redissonClient = redissonClient;
this.lockKey = lockKey;
}
public DefaultRedisLockSupport(String lockKey, long waitTime, long leaseTime) {
this.lockKey = lockKey;
this.waitTime = waitTime;
this.leaseTime = leaseTime;
}
public DefaultRedisLockSupport(RedissonClient redissonClient, String lockKey, long waitTime, long leaseTime) {
this.redissonClient = redissonClient;
this.lockKey = lockKey;
this.waitTime = waitTime;
this.leaseTime = leaseTime;
}
public DefaultRedisLockSupport(String lockKey, long waitTime, long leaseTime, TimeUnit unit) {
this.lockKey = lockKey;
this.waitTime = waitTime;
this.leaseTime = leaseTime;
this.unit = unit;
}
public DefaultRedisLockSupport(RedissonClient redissonClient, String lockKey, long waitTime, long leaseTime, TimeUnit unit) {
this.redissonClient = redissonClient;
this.lockKey = lockKey;
this.waitTime = waitTime;
this.leaseTime = leaseTime;
this.unit = unit;
}
@Override
public <P, R> R exec(Function<P, R> function, P param) throws NotAcquiredRedisLockException {
RedissonClient client = redissonClient();
RLock lock = client.getLock(lockKey);
boolean obtainLock = false;
try {
obtainLock = lock.tryLock(waitTime, leaseTime, unit);
} catch (InterruptedException e) {
// ignore
}
if (obtainLock) {
try {
return function.apply(param);
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
throw new NotAcquiredRedisLockException(lockKey, waitTime, unit);
}
@Override
public <R> R exec(NoArgFunction<R> function) throws NotAcquiredRedisLockException {
RedissonClient client = redissonClient();
RLock lock = client.getLock(lockKey);
boolean obtainLock = false;
try {
obtainLock = lock.tryLock(waitTime, leaseTime, unit);
} catch (InterruptedException e) {
// ignore
}
if (obtainLock) {
try {
return function.apply();
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
throw new NotAcquiredRedisLockException(lockKey, waitTime, unit);
}
@Override
public <P> void voidExec(Consumer<P> consumer, P param) throws NotAcquiredRedisLockException {
RedissonClient client = redissonClient();
RLock lock = client.getLock(lockKey);
boolean obtainLock = false;
try {
obtainLock = lock.tryLock(waitTime, leaseTime, unit);
} catch (InterruptedException e) {
// ignore
}
if (obtainLock) {
try {
consumer.accept(param);
return;
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
throw new NotAcquiredRedisLockException(lockKey, waitTime, unit);
}
@Override
public void voidExec(NoArgConsumer consumer) throws NotAcquiredRedisLockException {
RedissonClient client = redissonClient();
RLock lock = client.getLock(lockKey);
boolean obtainLock = false;
try {
obtainLock = lock.tryLock(waitTime, leaseTime, unit);
} catch (InterruptedException e) {
// ignore
}
if (obtainLock) {
try {
consumer.accept();
return;
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
throw new NotAcquiredRedisLockException(lockKey, waitTime, unit);
}
/** * obtain RedissonClient example * * @return RedissonClient example */
protected RedissonClient redissonClient() {
if (this.redissonClient != null) {
return this.redissonClient;
}
if (DefaultRedisLockSupport.defaultRedissonClient != null) {
return DefaultRedisLockSupport.defaultRedissonClient;
}
throw new IllegalStateException("There is not redissonClient available.");
}
/** * Initialize the default Redisson client * * @param redissonClient * Redisson Client instance */
public static void initDefaultRedissonClient(RedissonClient redissonClient) {
if (DefaultRedisLockSupport.defaultRedissonClient != null && !DefaultRedisLockSupport.defaultRedissonClient.equals(redissonClient)) {
throw new IllegalStateException("defaultRedissonClient already been initialized.");
}
synchronized (DefaultRedisLockSupport.class) {
if (DefaultRedisLockSupport.defaultRedissonClient != null) {
if (DefaultRedisLockSupport.defaultRedissonClient.equals(redissonClient)) {
return;
}
throw new IllegalStateException("defaultRedissonClient already been initialized.");
}
DefaultRedisLockSupport.defaultRedissonClient = redissonClient;
}
}
}
Two other interfaces involved in the tool class interface
-
NoArgConsumer
/** * No arguments Consumer * * @author JustryDeng * @since 2022/4/19 11:17 */ @FunctionalInterface public interface NoArgConsumer { /** * Perform logical */ void accept(); }
-
NoArgFunction
/** * No arguments Function * * @author JustryDeng * @since 2022/4/19 11:17 */ @FunctionalInterface public interface NoArgFunction<R> { /** * Perform logical * * @return Execution results */ R apply(); }
Examples of use
import com.ideaaedi.heywebuy.srv.config.redisson.DefaultRedisLockSupport;
import com.ideaaedi.heywebuy.srv.config.redisson.NoArgConsumer;
import com.ideaaedi.heywebuy.srv.config.redisson.NoArgFunction;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.redisson.api.RedissonClient;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
@Slf4j
@SpringBootTest
public class RedisLockSupportTest {
@Resource
private RedissonClient redissonClient;
@BeforeEach
void initMethod() {
// Inject... When the project starts
DefaultRedisLockSupport.initDefaultRedissonClient(redissonClient);
}
@Test
void test() {
// No parameter No return value NoArgConsumer
new DefaultRedisLockSupport("DefaultRedisLockSupport1", 1, 120).voidExec(new NoArgConsumer() {
@Override
public void accept() {
// I'm business logic
System.out.println("[ No parameter No return value NoArgConsumer]:\t\t\t\t\t" + 111111);
}
});
// With parameters No return value Consumer
new DefaultRedisLockSupport("DefaultRedisLockSupport1", 1, 120).voidExec(new Consumer<Integer>() {
@Override
public void accept(Integer s) {
// I'm business logic
System.out.println("[ With parameters No return value Consumer]:\t\t\t\t\t" + s);
}
}, 2222);
// No parameter There is a return value NoArgFunction
Map<String, Object> result = new DefaultRedisLockSupport("DefaultRedisLockSupport1", 1, 120)
.exec(new NoArgFunction<Map<String, Object>>() {
@Override
public Map<String, Object> apply() {
// I'm business logic
return Collections.singletonMap("k1", "v1");
}
} );
System.out.println("[ No parameter There is a return value Function]:\t\t\t\t\t" + result);
// With parameters There is a return value Function
result = new DefaultRedisLockSupport("DefaultRedisLockSupport1", 1, 120).exec(new Function<String, Map<String, Object>>() {
@Override
public Map<String, Object> apply(String s) {
// I'm business logic
return Collections.singletonMap("k2", s);
}
}, "v2");
System.out.println("[ With parameters There is a return value Function]:\t\t\t\t\t" + result);
}
}
Related information
- This article has been included in 《 Programmer growth notes 》 , The author JustryDeng
版权声明
本文为[justry_ deng]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/04/202204231923567429.html
边栏推荐
- Kubernetes入门到精通-KtConnect(全称Kubernetes Toolkit Connect)是一款基于Kubernetes环境用于提高本地测试联调效率的小工具。
- C语言的十六进制printf为何输出有时候输出带0xFF有时没有
- Using oes texture + glsurfaceview + JNI to realize player picture processing based on OpenGL es
- UML类图几种关系的总结
- 深度学习——特征工程小总结
- FFT物理意义: 1024点FFT就是1024个实数,实际进入fft的输入是1024个复数(虚部为0),输出也是1024个复数,有效的数据是前512个复数
- Go three ways to copy files
- 音频编辑生成软件
- [报告] Microsoft :Application of deep learning methods in speech enhancement
- 数据分析学习目录
猜你喜欢
Command - sudo
ArcMap publishing slicing service
山大网安靶场实验平台项目—个人记录(四)
arcMap 发布切片服务
RuntimeError: Providing a bool or integral fill value without setting the optional `dtype` or `out`
Decompile and get the source code of any wechat applet - just read this (latest)
Is meituan, a profit-making company with zero foundation, hungry? Coupon CPS applet (with source code)
First experience of using fluent canvas
Why is PostgreSQL about to surpass SQL Server?
Pdf reference learning notes
随机推荐
命令-sudo
ArcMap connecting ArcGIS Server
Machine learning catalog
Wechat applet part of the mobile phone Preview PDF did not respond
深度学习环境搭建步骤—gpu
arcgis js api dojoConfig配置
js上传文件时控制文件类型和大小
RuntimeError: Providing a bool or integral fill value without setting the optional `dtype` or `out`
Executor、ExecutorService、Executors、ThreadPoolExecutor、Future、Runnable、Callable
@MapperScan与@Mapper
How to use go code to compile Pb generated by proto file with protoc Compiler Go file
goroutine
Prefer composition to inheritance
数据分析学习目录
Kubernetes入门到精通-KtConnect(全称Kubernetes Toolkit Connect)是一款基于Kubernetes环境用于提高本地测试联调效率的小工具。
UML类图几种关系的总结
Pdf reference learning notes
Strange passion
精简CUDA教程——CUDA Driver API
SSDB foundation 3