当前位置:网站首页>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
边栏推荐
- Audio signal processing and coding - 2.5.3 the discrete cosine transform
- Common SQL commands
- Machine learning catalog
- How to use go code to compile Pb generated by proto file with protoc Compiler Go file
- SSDB foundation 3
- Oracle配置st_geometry
- Redis core technology and practice 1 - start with building a simple key value database simplekv
- Speculation on the way to realize the smooth drag preview of video editing software
- An algorithm problem was encountered during the interview_ Find the mirrored word pairs in the dictionary
- 考试系统进入试卷优化思路
猜你喜欢
深度学习——特征工程小总结
[report] Microsoft: application of deep learning methods in speech enhancement
Application of DCT transform
Oracle配置st_geometry
Using oes texture + glsurfaceview + JNI to realize player picture processing based on OpenGL es
First experience of using fluent canvas
Decompile and get the source code of any wechat applet - just read this (latest)
The platinum library cannot search the debug process records of some projection devices
2021-2022-2 ACM集训队每周程序设计竞赛(8)题解
MySQL syntax collation (2)
随机推荐
考试系统进入试卷优化思路
JVM的类加载过程
OpenHarmony开源开发者成长计划,寻找改变世界的开源新生力!
OpenHarmony开源开发者成长计划,寻找改变世界的开源新生力!
Decompile and get the source code of any wechat applet - just read this (latest)
I just want to leave a note for myself
命令-sudo
Audio signal processing and coding - 2.5.3 the discrete cosine transform
Go modules daily use
坐标转换WGS-84 转 GCJ-02 和 GCJ-02转WGS-84
[report] Microsoft: application of deep learning methods in speech enhancement
Easy mock local deployment (you need to experience three times in a crowded time. Li Zao will do the same as me. Love is like a festival mock)
IIS数据转换问题16bit转24bit
SQL of contention for system time plus time in ocrale database
Common SQL commands
【webrtc】Add x264 encoder for CEF/Chromium
MySQL syntax collation
深度学习——特征工程小总结
Reflection on the performance of some OpenGL operations in the past
The most detailed network counting experiment in history (2) -- rip experiment of layer 3 switch