Redisson分布式锁及springboot 整合实例
Redisson是一个Redis Java客户端,具有In-Memory Data Grid的功能。它提供了更方便和最简单的方法来使用 Redis。Redisson 对象提供了关注点分离,使您可以专注于数据建模和应用程序逻辑。
基于高性能异步和无锁的Java Redis客户端和Netty框架。
支持的 JDK:1.8 ...19 和安卓
支持的 Redis: 3.0 ...7.0
官网:1. Overview · redisson/redisson Wiki (github.com)
一、特征:
线程安全实现
支持 Redis 复制、Redis 集群、Redis Sentinel、Redis 主从、Redis 单一设置
支持 AWS ElastiCache、Amazon MemoryDB、Azure Redis Cache、Google Cloud Memorystore for Redis、Redis Enterprise、Aiven for Redis
支持自动重连
支持发送失败命令自动重试
支持OSGi
支持静态服务器
异步连接池
Lua 脚本编写
JSON 数据类型
反应流应用程序接口
RxJava3应用程序接口
异步应用程序接口
本地缓存支持,包括基于Caffeine-based的实现
分布式 Java 对象 对象
持有者、二进制流持有者、地理空间持有者、BitSet、AtomicLong、AtomicDouble、PublishSubscribe、 布隆过滤器、超日志日志
分布式 Java 集合 映射, 多重映射, 集合
, 列表, 排序集, 得分排序集, LexSortedSet, 队列, 双端克, 阻塞队列, 有界阻塞队列, 阻塞双节, 延迟队列, 优先级队列, 优先级双端
分布式 Java 锁和同步器
Lock、FairLock、MultiLock、RedLock、ReadWriteLock、Semaphore、PermitExpirableSemaphore、CountDownLatch
分布式服务 远程服务、活对象服务、执行器服务、调度程序服务、MapReduce 服务
二、分布式锁和同步器
1、锁定
基于 Redis 的分布式重入 Lock 对象 Java 并实现 Lock 接口。如果获取锁的 Redisson 实例崩溃,则此类锁可以永远处于获取状态。为了避免这种情况 Redisson 维护锁看门狗,它会在锁持有人 Redisson 实例处于活动状态时延长锁过期时间。默认情况下,锁定看门狗超时为 30 秒,可以通过 Config.lockWatchdogTimeout 设置进行更改。leaseTime可以定义锁采集期间的参数。在指定的时间间隔后,锁定的锁将自动释放。RLock对象的行为符合 Java Lock 规范。这意味着只有锁所有者线程才能解锁它,否则会被抛出。否则,请考虑使用 RSemaphore 对象。
代码示例:
RLock lock = redisson.getLock("myLock");// traditional lock method
lock.lock();// or acquire lock and automatically unlock it after 10 seconds
lock.lock(10, TimeUnit.SECONDS);// or wait for lock aquisition up to 100 seconds
// and automatically unlock it after 10 seconds
boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
if (res) {try {...} finally {lock.unlock();}
}
异步接口用法的代码示例:
RLock lock = redisson.getLock("myLock");RFuture<Void> lockFuture = lock.lockAsync();// or acquire lock and automatically unlock it after 10 seconds
RFuture<Void> lockFuture = lock.lockAsync(10, TimeUnit.SECONDS);// or wait for lock aquisition up to 100 seconds
// and automatically unlock it after 10 seconds
RFuture<Boolean> lockFuture = lock.tryLockAsync(100, 10, TimeUnit.SECONDS);lockFuture.whenComplete((res, exception) -> {// ...lock.unlockAsync();
});
反应式接口用法的代码示例:
edissonReactiveClient redisson = redissonClient.reactive();
RLockReactive lock = redisson.getLock("myLock");Mono<Void> lockMono = lock.lock();// or acquire lock and automatically unlock it after 10 seconds
Mono<Void> lockMono = lock.lock(10, TimeUnit.SECONDS);// or wait for lock aquisition up to 100 seconds
// and automatically unlock it after 10 seconds
Mono<Boolean> lockMono = lock.tryLock(100, 10, TimeUnit.SECONDS);lockMono.doOnNext(res -> {// ...
})
.doFinally(lock.unlock())
.subscribe();
RxJava3 接口使用的代码示例:
RedissonRxClient redisson = redissonClient.rxJava();
RLockRx lock = redisson.getLock("myLock");Completable lockRes = lock.lock();
// or acquire lock and automatically unlock it after 10 seconds
Completable lockRes = lock.lock(10, TimeUnit.SECONDS);
// or wait for lock aquisition up to 100 seconds
// and automatically unlock it after 10 seconds
Single<Boolean> lockRes = lock.tryLock(100, 10, TimeUnit.SECONDS);
lockRes.doOnSuccess(res -> {// ...
})
.doFinally(lock.unlock())
.subscribe();
2、公平锁定
基于 Redis 的分布式重入公平 Java 的 Lock 对象实现了 Lock 接口。
公平锁保证线程将按照与请求相同的顺序获取它。所有等待的线程都已排队,如果某个线程已死亡,则 Redisson 将等待其返回 5 秒。例如,如果 5 个线程由于某种原因死亡,则延迟将为 25 秒。
如果获取锁的 Redisson 实例崩溃,则此类锁可以永远处于获取状态。为了避免这种情况 Redisson 维护锁看门狗,它会在锁持有人 Redisson 实例处于活动状态时延长锁过期时间。默认情况下,锁定看门狗超时为 30 秒,可以通过 Config.lockWatchdogTimeout 设置进行更改。
leaseTime可以定义锁采集期间的参数。在指定的时间间隔后,锁定的锁将自动释放。
RLock对象的行为符合 Java Lock 规范。这意味着只有锁所有者线程才能解锁它,否则会被抛出。否则,请考虑使用 RSemaphore 对象。
代码示例:
RLock lock = redisson.getFairLock("myLock");// traditional lock method
lock.lock();// or acquire lock and automatically unlock it after 10 seconds
lock.lock(10, TimeUnit.SECONDS);// or wait for lock aquisition up to 100 seconds
// and automatically unlock it after 10 seconds
boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
if (res) {try {...} finally {lock.unlock();}
}
3、 多重锁
基于 Redis 的分布式对象允许对 Lock 对象进行分组并将它们作为单个锁处理。每个对象可能属于不同的 Redisson 实例。MultiLockRLock
如果获取的 Redisson 实例崩溃,那么该实例可能会永远处于获取状态。为了避免这种情况 Redisson 维护锁看门狗,它会在锁持有人 Redisson 实例处于活动状态时延长锁过期时间。默认情况下,锁定看门狗超时为 30 秒,可以通过 Config.lockWatchdogTimeout 设置进行更改。MultiLockMultiLock
leaseTime可以定义锁采集期间的参数。在指定的时间间隔后,锁定的锁将自动释放。
MultiLock对象的行为符合 Java Lock 规范。这意味着只有锁所有者线程才能解锁它,否则会被抛出。否则,请考虑使用 RSemaphore 对象
RLock lock1 = redisson1.getLock("lock1");
RLock lock2 = redisson2.getLock("lock2");
RLock lock3 = redisson3.getLock("lock3");RLock multiLock = anyRedisson.getMultiLock(lock1, lock2, lock3);// traditional lock method
multiLock.lock();// or acquire lock and automatically unlock it after 10 seconds
multiLock.lock(10, TimeUnit.SECONDS);// or wait for lock aquisition up to 100 seconds
// and automatically unlock it after 10 seconds
boolean res = multiLock.tryLock(100, 10, TimeUnit.SECONDS);
if (res) {try {...} finally {multiLock.unlock();}
}
异步接口用法的代码示例:
RLock lock1 = redisson1.getLock("lock1");
RLock lock2 = redisson2.getLock("lock2");
RLock lock3 = redisson3.getLock("lock3");RLock multiLock = anyRedisson.getMultiLock(lock1, lock2, lock3);RFuture<Void> lockFuture = multiLock.lockAsync();// or acquire lock and automatically unlock it after 10 seconds
RFuture<Void> lockFuture = multiLock.lockAsync(10, TimeUnit.SECONDS);// or wait for lock aquisition up to 100 seconds
// and automatically unlock it after 10 seconds
RFuture<Boolean> lockFuture = multiLock.tryLockAsync(100, 10, TimeUnit.SECONDS);lockFuture.whenComplete((res, exception) -> {// ...multiLock.unlockAsync();
});
反应式接口用法的代码示例:
RedissonReactiveClient anyRedisson = redissonClient.reactive();RLockReactive lock1 = redisson1.getLock("lock1");
RLockReactive lock2 = redisson2.getLock("lock2");
RLockReactive lock3 = redisson3.getLock("lock3");RLockReactive multiLock = anyRedisson.getMultiLock(lock1, lock2, lock3);Mono<Void> lockMono = multiLock.lock();// or acquire lock and automatically unlock it after 10 seconds
Mono<Void> lockMono = multiLock.lock(10, TimeUnit.SECONDS);// or wait for lock aquisition up to 100 seconds
// and automatically unlock it after 10 seconds
Mono<Boolean> lockMono = multiLock.tryLock(100, 10, TimeUnit.SECONDS);lockMono.doOnNext(res -> {// ...
})
.doFinally(multiLock.unlock())
.subscribe();
4、 读写锁定
基于 Redis 的分布式重入器 ReadWriteLock 对象 for Java 实现了 ReadWriteLock 接口。读锁和写锁都实现 RLock 接口。
允许多个 ReadLock 所有者和仅允许一个 WriteLock 所有者。
如果获取锁的 Redisson 实例崩溃,则此类锁可以永远处于获取状态。为了避免这种情况 Redisson 维护锁看门狗,它会在锁持有人 Redisson 实例处于活动状态时延长锁过期时间。默认情况下,锁定看门狗超时为 30 秒,可以通过 Config.lockWatchdogTimeout 设置进行更改。
Redisson还允许在锁采集期间指定参数。在指定的时间间隔后,锁定的锁将自动释放。leaseTime
RLock对象的行为符合 Java Lock 规范。这意味着只有锁所有者线程才能解锁它,否则会被抛出。否则,请考虑使用 RSemaphore 对象。
RReadWriteLock rwlock = redisson.getReadWriteLock("myLock");RLock lock = rwlock.readLock();
// or
RLock lock = rwlock.writeLock();// traditional lock method
lock.lock();// or acquire lock and automatically unlock it after 10 seconds
lock.lock(10, TimeUnit.SECONDS);// or wait for lock aquisition up to 100 seconds
// and automatically unlock it after 10 seconds
boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
if (res) {try {...} finally {lock.unlock();}
}
异步接口用法的代码示例:
RReadWriteLock rwlock = redisson.getReadWriteLock("myLock");RLock lock = rwlock.readLock();
// or
RLock lock = rwlock.writeLock();RFuture<Void> lockFuture = lock.lockAsync();// or acquire lock and automatically unlock it after 10 seconds
RFuture<Void> lockFuture = lock.lockAsync(10, TimeUnit.SECONDS);// or wait for lock aquisition up to 100 seconds
// and automatically unlock it after 10 seconds
RFuture<Boolean> lockFuture = lock.tryLockAsync(100, 10, TimeUnit.SECONDS);lockFuture.whenComplete((res, exception) -> {// ...lock.unlockAsync();
});
反应式接口用法的代码示例:
RedissonReactiveClient redisson = redissonClient.reactive();RReadWriteLockReactive rwlock = redisson.getReadWriteLock("myLock");RLockReactive lock = rwlock.readLock();
// or
RLockReactive lock = rwlock.writeLock();Mono<Void> lockMono = lock.lock();// or acquire lock and automatically unlock it after 10 seconds
Mono<Void> lockMono = lock.lock(10, TimeUnit.SECONDS);// or wait for lock aquisition up to 100 seconds
// and automatically unlock it after 10 seconds
Mono<Boolean> lockMono = lock.tryLock(100, 10, TimeUnit.SECONDS);lockMono.doOnNext(res -> {// ...
})
.doFinally(lock.unlock())
.subscribe();
5、信号量
基于 Redis 的分布式 Java 信号量对象类似于 Semaphore 对象。
可以在使用前初始化,但这不是必需的,通过方法提供可用的许可证数量
RSemaphore semaphore = redisson.getSemaphore("mySemaphore");// acquire single permit
semaphore.acquire();// or acquire 10 permits
semaphore.acquire(10);// or try to acquire permit
boolean res = semaphore.tryAcquire();// or try to acquire permit or wait up to 15 seconds
boolean res = semaphore.tryAcquire(15, TimeUnit.SECONDS);// or try to acquire 10 permit
boolean res = semaphore.tryAcquire(10);// or try to acquire 10 permits or wait up to 15 seconds
boolean res = semaphore.tryAcquire(10, 15, TimeUnit.SECONDS);
if (res) {try {...} finally {semaphore.release();}
}
6、 允许可过期信号量
基于 Redis 的分布式 Java 信号量对象,每个获取的许可证都支持租用时间参数。每个许可证都由自己的身份证标识,只能使用其身份证签发。
应在使用前初始化,通过方法使用可用的许可金额。允许通过方法增加/减少可用许可证的数量。
代码示例:
RPermitExpirableSemaphore semaphore = redisson.getPermitExpirableSemaphore("mySemaphore");semaphore.trySetPermits(23);// acquire permit
String id = semaphore.acquire();// or acquire permit with lease time in 10 seconds
String id = semaphore.acquire(10, TimeUnit.SECONDS);// or try to acquire permit
String id = semaphore.tryAcquire();// or try to acquire permit or wait up to 15 seconds
String id = semaphore.tryAcquire(15, TimeUnit.SECONDS);// or try to acquire permit with least time 15 seconds or wait up to 10 seconds
String id = semaphore.tryAcquire(10, 15, TimeUnit.SECONDS);
if (id != null) {try {...} finally {semaphore.release(id);}
}
7、倒计时锁存器
基于 Redis 的分布式 CountDownLatch 对象 Java 具有类似于 CountDownLatch 对象的结构。
使用前应使用 count by 方法初始化
RCountDownLatch latch = redisson.getCountDownLatch("myCountDownLatch");latch.trySetCount(1);
// await for count down
latch.await();// in other thread or JVM
RCountDownLatch latch = redisson.getCountDownLatch("myCountDownLatch");
latch.countDown();
8、旋转锁定
基于Redis的分布式重入器SpinLock对象用于Java并实现Lock接口。
由于 Lock 对象中的 pubsub 使用率,每个短时间间隔获取/释放的数千个或更多锁可能会导致达到网络吞吐量限制和 Redis CPU 过载。这是由于 Redis pubsub 的性质 - 消息被分发到 Redis 集群中的所有节点。默认情况下,旋转锁定使用指数退避策略进行锁定获取,而不是发布子通道。
如果获取锁的 Redisson 实例崩溃,则此类锁可以永远处于获取状态。为了避免这种情况 Redisson 维护锁看门狗,它会在锁持有人 Redisson 实例处于活动状态时延长锁过期时间。默认情况下,锁定看门狗超时为 30 秒,可以通过 Config.lockWatchdogTimeout 设置进行更改。
leaseTime可以定义锁采集期间的参数。在指定的时间间隔后,锁定的锁将自动释放。
RLock对象的行为符合 Java Lock 规范。这意味着只有锁所有者线程才能解锁它,否则会被抛出。否则,请考虑使用 RSemaphore 对象
RLock lock = redisson.getSpinLock("myLock");// traditional lock method
lock.lock();// or acquire lock and automatically unlock it after 10 seconds
lock.lock(10, TimeUnit.SECONDS);// or wait for lock aquisition up to 100 seconds
// and automatically unlock it after 10 seconds
boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
if (res) {try {...} finally {lock.unlock();}
}
9、 围栏锁
基于Redis的分布式重入器FencedLock对象用于Java并实现Lock接口。
这种类型的锁维护屏蔽令牌,以避免客户端获取锁由于长时间的 GC 暂停或其他原因而延迟,并且无法检测到它不再拥有锁的情况。要解决此问题,令牌通过锁定方法或方法返回。应通过此锁保护的服务检查令牌是否大于或等于前一个令牌,如果条件为 false,则应拒绝操作。getToken()
如果获取锁的 Redisson 实例崩溃,则此类锁可以永远处于获取状态。为了避免这种情况 Redisson 维护锁看门狗,它会在锁持有人 Redisson 实例处于活动状态时延长锁过期时间。默认情况下,锁定看门狗超时为 30 秒,可以通过 Config.lockWatchdogTimeout 设置进行更改。
leaseTime可以定义锁采集期间的参数。在指定的时间间隔后,锁定的锁将自动释放。
RLock对象的行为符合 Java Lock 规范。这意味着只有锁所有者线程才能解锁它,否则会被抛出。否则,请考虑使用 RSemaphore 对象。
RFencedLock lock = redisson.getFencedLock("myLock");// traditional lock method
Long token = lock.lockAndGetToken();// or acquire lock and automatically unlock it after 10 seconds
token = lock.lockAndGetToken(10, TimeUnit.SECONDS);// or wait for lock aquisition up to 100 seconds
// and automatically unlock it after 10 seconds
Long token = lock.tryLockAndGetToken(100, 10, TimeUnit.SECONDS);
if (token != null) {try {// check if token >= old token...} finally {lock.unlock();}
}
异步接口用法的代码示例:
RFencedLock lock = redisson.getFencedLock("myLock");RFuture<Long> lockFuture = lock.lockAndGetTokenAsync();// or acquire lock and automatically unlock it after 10 seconds
RFuture<Long> lockFuture = lock.lockAndGetTokenAsync(10, TimeUnit.SECONDS);// or wait for lock aquisition up to 100 seconds
// and automatically unlock it after 10 seconds
RFuture<Long> lockFuture = lock.tryLockAndGetTokenAsync(100, 10, TimeUnit.SECONDS);long threadId = Thread.currentThread().getId();
lockFuture.whenComplete((token, exception) -> {if (token != null) {try {// check if token >= old token...} finally {lock.unlockAsync(threadId);}}
});
三、开发实例
1、 依赖引入:
<dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.19.2</version>
</dependency>
2、参数配置
spring:redis:cluster:nodeAddresses: ["redis://127.0.0.1:7005","redis://127.0.0.1:7004","redis://127.0.0.1:7003","redis://127.0.0.1:7002","redis://127.0.0.1:7001","redis://127.0.0.1:7000"]password: 99999single:address: "redis://127.0.0.1:6379"database: 7
3、配置参数读取类
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;import java.io.Serializable;
import java.util.List;@Data
@Component
@ConfigurationProperties(prefix = "spring.redis")
public class RedisConfigProperties implements Serializable {private static final long serialVersionUID = 8815222005846355408L;private String password;private cluster cluster;private Single single;public static class cluster {private List<String> nodeAddresses;public List<String> getNodeAddresses() {return nodeAddresses;}public void setNodeAddresses(List<String> nodeAddresses) {this.nodeAddresses = nodeAddresses;}@Overridepublic String toString() {return "{" +"nodeAddresses=" + nodeAddresses +'}';}}public static class Single {private String address;public Integer database;public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}public Integer getDatabase() {return database;}public void setDatabase(Integer database) {this.database = database;}@Overridepublic String toString() {return "Single{" +"address='" + address + '\'' +", database=" + database +'}';}}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public RedisConfigProperties.cluster getCluster() {return cluster;}public void setCluster(RedisConfigProperties.cluster cluster) {this.cluster = cluster;}
}
4、Redisson 客户端配置
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.client.codec.StringCodec;
import org.redisson.config.ClusterServersConfig;
import org.redisson.config.Config;
import org.redisson.config.SingleServerConfig;
import org.redisson.config.TransportMode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.io.IOException;
import java.util.List;
@Slf4j
@Configuration
public class MyRedissonConfig {@Autowired(required = false)private RedisConfigProperties redisConfigProperties;/*** 配置redisson单机* @return*/@Beanpublic RedissonClient redissonClient() {Config config = new Config();config.setTransportMode(TransportMode.EPOLL); // 默认是NIO的方式config.useClusterServers()//可以用"rediss://"来启用SSL连接,前缀必须是redis:// or rediss://.addNodeAddress("redis://127.0.0.1:7181");return Redisson.create(config);}/*** 配置redisson集群* @return*/@Bean(destroyMethod = "shutdown")public RedissonClient getRedissonClient() {List<String> clusterNodes = redisConfigProperties.getCluster().getNodeAddresses();Config config = new Config();//对象编码选择纯字符串编码config.setCodec(StringCodec.INSTANCE);ClusterServersConfig clusterServersConfig = config.useClusterServers().addNodeAddress(clusterNodes.toArray(new String[clusterNodes.size()]));//设置密码clusterServersConfig.setPassword(redisConfigProperties.getPassword());//redis连接心跳检测,防止一段时间过后,与redis的连接断开clusterServersConfig.setPingConnectionInterval(32000);return Redisson.create(config);}}
5、测试代码:
@Autowiredprivate RedissonClient redissonClient;private static void test() {RBucket<Object> bucket = redissonClient.getBucket("string-demo");bucket.set("hello");System.out.println(bucket.get());}
Redisson分布式锁及springboot 整合实例相关推荐
- redisson分布式锁,实战
目录 什么时候用分布式锁? 分布式锁入门 超时设置 释放了不是自己加的锁 正确设置锁超时 加解锁代码位置有讲究 实现可重入锁 Redis Hash 可重入锁 主从架构带来的问题 什么是 Redlock ...
- Jmeter Springboot Redisson分布式锁并发订单操作(下单、取消单、完成单、加库存)
Jmeter+Springboot+Redisson分布式锁并发订单操作(下单.取消单.完成单.加库存) 涉及知识点: java+springboot+mybatis开发 redis分布式锁+Redi ...
- springboot基础(72):Redisson分布式锁
文章目录 前言 第一节 入门使用Redisson 第二节 注解形式的分布式锁 1. 分布式锁的注解实现 2. 分析MyRedissonLock注解和使用 传送门 前言 并发执行是比较场景的场景,单机情 ...
- Redisson分布式锁实战-1:构建分布式锁
我们现在来到Task类当中,这个方法就是V4了/*** Redisson分布式锁实现* @throws InterruptedException*/ // @Scheduled(cron=" ...
- 年轻人,看看 Redisson 分布式锁—可重入锁吧!太重要了
作者 | 李祥 责编 | 张文 来源 | 企鹅杏仁技术站(ID:xingren-tech) 引言 作为后端开发,对于所谓的线程安全.高并发等一系列名词肯定都不会陌生,相关的一些概念及技术框架是面 ...
- Redisson分布式锁的配置和使用
基于springBoot的redisson分布式锁 之前使用Redis分布式锁都是自己写的工具类,利用Redis的setNX特性:后来发现Redisson提供的分布式锁是真的好用. Redisson可 ...
- redis ,redisson 分布式锁深入剖析
目录 为什么要用分布式锁? 分布式锁所遵循的原则? redis 分布式锁 redis 原始分布式锁实现 加锁 释放锁 redis 分布式锁存在的问题 redisson 实现分布式锁 redisson ...
- 年轻人,看看Redisson分布式锁—可重入锁吧!太重要了
1.引言 作为后端开发,对于所谓的线程安全.高并发等一系列名词肯定都不会陌生,相关的一些概念及技术框架是面试中的宠儿,也是工作中解决一些特定场景下的技术问题的银弹.今天我们就来聊聊这些银弹中的其中一枚 ...
- Redis进阶- Redisson分布式锁实现原理及源码解析
文章目录 Pre 用法 Redisson分布式锁实现原理 Redisson分布式锁源码分析 redisson.getLock(lockKey) 的逻辑 redissonLock.lock()的逻辑 r ...
最新文章
- Spark学习之Spark RDD算子
- mysql数据库二级233_MySQL数据库开发必备常识
- R语言数据挖掘实践——系谱聚类
- 深入理解Javascript之执行上下文(Execution Context)
- picturectrl控件中加载图片并显示_在 CRA 中使用 webp 图片提升加载性能
- 解决:RabbitMQ 连接报错:amqp.AmqpConnectException: java.net.ConnectException: Connection refused: connect
- QNX下挂载USB设备
- 来了!iPhone 12今晚天猫首销:12期分期免息,还送5G流量包
- 固态硬盘新趋势?美光3D QLC闪存出货量猛增75%
- Extjs grid禁用头部点击三角下拉菜单
- SC-RoadDeepNet学习笔记
- 步进式解读Apache许可证
- MD5,SHA1,SHA256,NTLM,LM等Hash在线破解网站收集
- python字符串str拼接
- 阿里云云边一体容器架构创新论文被云计算顶会 ACM SoCC 录用
- matlab解五元方程,哪位大侠帮忙解这个五元四次方程组
- 安装版—安装MySQL
- 防止你的WP7手机偷跑流量——系统设置篇
- 下载的软件包保存在缓存中,直到下次成功执行事务。 您可以通过执行 'dnf clean packages' 删除软件包缓存。 错误:事务检查错误
- c语言表示三个数除却最大最小,湖南师范大l历年年语言学及应用语言学现代汉语考研试题.doc...
热门文章
- mini-spinner格式化
- unity c#非法字符(脏词)检测
- 公司服务器被攻破后的处理
- 麻将胡牌算番-台州麻将
- 为奥运喝彩!百度智能云联合央视体育客户端打造奥运播报新体验!
- 使用 Python 进行 GUI 掷骰子模拟
- 阿里巴巴2016校园招聘 研发工程师(四)详解
- python.列表全方位解读
- 2006年美国福布斯“全球富豪榜”
- [Warning] implicit declaration of function ‘clrscr‘ [-Wimplicit-function-declaration]