string 的2种数据结构,3种编码方式
string结构图
2种数据结构
int:value值是一个整数类型,
SDS:value是字符串类型
3种编码方式
1.int
如果一个字符串对象保存的是一个整数值,那么此字符串的编码是int
结构:
2.embstr
如果字符串的长度在小于44个字节(总字节数小于64个字节)使用的编码方式是embstr方式。由内存分配器一次分配RedisObject和sdshdr
结构:
3.raw
如果字符串的长度大于44个字节(总字节数大于64个字节),此时redis认为这是一个大字符串,使用的编码方式是raw方式。由内存分配器俩次分配RedisObject和sdshdr
结构:
embstr和raw的区别
1.embstr使用一次内存分配,raw使用俩次没存分配。在数据量小的情况下使用embstr方式可以减少寻址时间
2.内存回收次数也不一样,embstr只需要一次。raw需要俩次
扩容方式
字符串长度在小于1M的情况下,每次追加如果能容纳下新增加的字符串长度,那么不做任何操作,反之扩容为原来的一倍。如果字符串长度大于1M。之后的扩容只会扩1M的冗余空间,防止浪费.
string常用功能
1.做缓存。value可以是一个普通字符串,也可以是json对象
2.计数器。int类型可以通过incr每次加一 或者incrby 加指定数
3.分布式锁
public class RedisLock {
private static final String LOCK_SUCCESS = "OK";
private static final Long RELEASE_SUCCESS = 1L;
// 锁的默认超时时间
private int expireTime = 10 * 1000;
// 锁默认等待时间
private int waitTime = 5 * 1000;
private Jedis jedis;
private String key;
/**
* 分布式环境下应该使用分布式id
*/
private String value = null;
public RedisLock(Jedis jedis, String key) {
this.jedis = jedis;
this.key = key;
}
public RedisLock(Jedis jedis, String key, int expireTime, int waitTime) {
this.jedis = jedis;
this.key = key;
this.expireTime = expireTime;
this.waitTime = waitTime;
}
/***
* 加锁
* @param value 分布式id
* @return
*/
public synchronized boolean lock(String value) {
if (value == null) {
throw new RuntimeException("value is null");
}
try {
// 超过等待时间,加锁失败
long waitEnd = System.currentTimeMillis() + waitTime + 1;
SetParams setParams = new SetParams();
setParams.nx();
setParams.px(expireTime);
while (System.currentTimeMillis() < waitEnd) {
String result = jedis.set(key, value, setParams);
if (LOCK_SUCCESS.equals(result)) {
this.value = value;
return true;
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
} catch (Exception ex) {
}
return false;
}
/***
* 释放锁
* @return
*/
public synchronized boolean unLock() {
if (value == null) {
return false;
}
//判断key和删除key必须是一个原子操作
String lua = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
try {
Object result = jedis.eval(lua, Collections.singletonList(key), Collections.singletonList(value));
if (RELEASE_SUCCESS.equals(result)) {
return true;
}
} catch (Exception e) {
}
return false;
}
}
public class JedisLock {
private final Jedis client;
private final String lockKey;
private final int expireTime;
private final int waitTime;
private boolean locked = false;
public JedisLock(Jedis client, String lockKey, int expireTime, int waitTime) {
this.client = client;
this.lockKey = lockKey;
this.expireTime = expireTime;
this.waitTime = waitTime;
}
public synchronized boolean lock() throws InterruptedException {
int timeout = this.waitTime;
while(timeout >= 0) {
long expires = System.currentTimeMillis() + (long)this.expireTime + 1L;
String expiresStr = String.valueOf(expires);
if (this.client.setNx(this.lockKey, expiresStr)) {
this.locked = true;
return true;
}
String currentValueStr = this.client.get(this.lockKey);
if (currentValueStr != null && Long.parseLong(currentValueStr) < System.currentTimeMillis()) {
String oldValueStr = this.client.getSet(this.lockKey, expiresStr);
if (oldValueStr != null && oldValueStr.equals(currentValueStr)) {
this.locked = true;
return true;
}
}
timeout -= 50;
this.wait(50L);
}
return false;
}
public synchronized void unlock() {
if (this.locked) {
this.client.delKey(this.lockKey);
this.locked = false;
}
}