当前位置:网站首页>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
边栏推荐
- Quick start to static class variables
- Openharmony open source developer growth plan, looking for new open source forces that change the world!
- 考试系统进入试卷优化思路
- No, some people can't do the National Day avatar applet (you can open the traffic master and earn pocket money)
- Golang timer
- An example of using JNI to directly access surface data
- 【h264】libvlc 老版本的 hevc h264 解析,帧率设定
- Machine learning catalog
- Using oes texture + glsurfaceview + JNI to realize player picture processing based on OpenGL es
- Grafana 分享带可变参数的链接
猜你喜欢

精简CUDA教程——CUDA Driver API

Application of DCT transform

An algorithm problem was encountered during the interview_ Find the mirrored word pairs in the dictionary

OpenHarmony开源开发者成长计划,寻找改变世界的开源新生力!

Using oes texture + glsurfaceview + JNI to realize player picture processing based on OpenGL es

2021-2022-2 ACM training team weekly Programming Competition (8) problem solution

深度学习——特征工程小总结

OpenHarmony开源开发者成长计划,寻找改变世界的开源新生力!

山大网安靶场实验平台项目—个人记录(四)

Use of fluent custom fonts and pictures
随机推荐
考试系统进入试卷优化思路
对普通bean进行Autowired字段注入
精简CUDA教程——CUDA Driver API
Pit encountered using camera x_ When onpause, the camera is not released, resulting in a black screen when it comes back
ArcMap连接 arcgis server
Pdf reference learning notes
arcgis js api dojoConfig配置
Go recursively loops through folders
RuntimeError: Providing a bool or integral fill value without setting the optional `dtype` or `out`
【webrtc】Add x264 encoder for CEF/Chromium
SSDB foundation 2
MySQL syntax collation (4)
Codeworks round 783 (Div. 2) d problem solution
js上传文件时控制文件类型和大小
Wechat applet part of the mobile phone Preview PDF did not respond
An algorithm problem was encountered during the interview_ Find the mirrored word pairs in the dictionary
goroutine
MFC获取本机IP(网络通讯时用得多)
Class loading mechanism
JVM的类加载过程