当前位置:网站首页>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
边栏推荐
- @MapperScan与@Mapper
- SSDB Foundation
- 山大网安靶场实验平台项目-个人记录(五)
- Data analysis learning directory
- Why is PostgreSQL about to surpass SQL Server?
- Steps to build a deep learning environment GPU
- 坐标转换WGS-84 转 GCJ-02 和 GCJ-02转WGS-84
- DevOps集成-Jenkins 服务的环境变量和构建工具 Tools
- Strange passion
- 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)
猜你喜欢

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

Redis optimization series (III) solve common problems after master-slave configuration

On the forced conversion of C language pointer

Intuitive understanding of the essence of two-dimensional rotation

Wechat applet part of the mobile phone Preview PDF did not respond

Network protocol: SCTP flow control transmission protocol
![[report] Microsoft: application of deep learning methods in speech enhancement](/img/c1/7bffbcecababf8dabf86bd34ab1809.png)
[report] Microsoft: application of deep learning methods in speech enhancement

Prefer composition to inheritance

Audio signal processing and coding - 2.5.3 the discrete cosine transform

arcMap 发布切片服务
随机推荐
SQL server requires to query the information of all employees with surname 'Wang'
Common SQL commands
山大网安靶场实验平台项目—个人记录(四)
JS calculation time difference
Intuitive understanding of the essence of two-dimensional rotation
[报告] Microsoft :Application of deep learning methods in speech enhancement
Kubernetes入门到精通-在 Kubernetes 上安装 OpenELB
Translation of audio signal processing and coding: Preface
对普通bean进行Autowired字段注入
An example of using JNI to directly access surface data
Go recursively loops through folders
How to uninstall easyton
Golang timer
2021-2022-2 ACM training team weekly Programming Competition (8) problem solution
Command - sudo
Modify the font size of hint in editext
Kubernetes入门到精通-裸机LoadBalence 80 443 端口暴露注意事项
OpenHarmony开源开发者成长计划,寻找改变世界的开源新生力!
Speex维纳滤波与超几何分布的改写
深度学习环境搭建步骤—gpu