总结:redis的每个操作是原子操作,但是在java代码中组合起来的redis操作不是原子操作,因此需要借用redis来实现分布式锁,解决并发问题。
虽然redis的操作是原子操作,但如果在java中分步操作的话,依旧会出现并发问题。
例如:先获取redis中的number,加1后再放回redis,如果10个线程同时处理的话,会出现并发问题。
public class test {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
Redis ru = new Redis();
//获取redis的值
Integer number= ru.getInteger("number");
number++;
//加一再放回redis
ru.set("number",number.toString());
System.out.println(Thread.currentThread().getName() +"---->result:" + number) ;
}
});
thread1.start();
}
}
}
结果为
在redis中的数据如图
image.png
由于初始number为0,运行10次后,应该为10,但是数据库中的number值为1,出现了错误。因为虽然redis的set和get操作是原子操作,但是在java代码中这两步分开了 ,所以还是没法兼容多线程的操作。后面我们会慢慢介绍如何通过redis的原子操作解决多线程并发的问题。
附java中操作jedis的代码:
package com.dazhiyouqiu.api;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public class Redis {
private Jedis jedis;
private JedisPool jedisPool;
public Redis() {
initialPool();
jedis = jedisPool.getResource();
}
private void initialPool() {
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxWaitMillis(100000l);
config.setMaxIdle(20);
config.setTestOnBorrow(false);
jedisPool = new JedisPool(config, "127.0.0.1", 6379,100000);
}
public String get(String key) {
String getStr = jedis.get(key);
return getStr;
}
public Integer getInteger(String key){
String re =jedis.get(key);
return re==null?0:Integer.valueOf(re);
}
public String set(String key, String value) {
String setStr = jedis.set(key, value);
return setStr;
}
public Long delete(String key){
Long re =jedis.del(key);
return re;
}
// NX是不存在时才set, XX是存在时才set, EX是秒,PX是毫秒
public String set(String key, String value,long expireSecond) {
String setStr = jedis.set(key, value,"NX","EX",expireSecond);
return setStr;
}
}
网友评论