• 从redis中取值如果不存在设置值,使用Redisson分布式锁【我】以及不使用锁的方式


    用到的jar包:

        <!-- Redis客户端 -->
            <dependency>
                <groupId>redis.clients</groupId>
                <artifactId>jedis</artifactId>
                <version>2.7.2</version>
            </dependency>
            
            <!-- redisson -->
             <dependency>
                <groupId>org.redisson</groupId>
                <artifactId>redisson</artifactId>
                <version>3.8.1</version>
            </dependency>

    测试代码:

    package redis;
    
    import org.redisson.Redisson;
    import org.redisson.api.RLock;
    import org.redisson.api.RedissonClient;
    import org.redisson.config.Config;
    
    import redis.clients.jedis.Jedis;
    import redis.clients.jedis.JedisPool;
    
    public class RedisThread {
    
        public static void main1(String[] args) {
            for (int i = 0; i < 3; i++) {
    //            final int k = i;
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        for (int j = 0; j < 10; j++) {
                            int k = j;
                            // 连接本地的 Redis 服务
    //                        Jedis jedis = new Jedis("localhost");
                            // 创建连接池对象
                            JedisPool jedisPool = new JedisPool("127.0.0.1", 6379);
                            // 从连接池中获取一个jedis对象
                            Jedis jedis = jedisPool.getResource();
    //                        synchronized (RedisThread.class) {
                            String v = jedis.get("a" + k);
    //                            if (v == null) {
                            if (!jedis.exists("a" + k)) {
                                jedis.set("a" + k, Thread.currentThread().getName());
                                jedis.expire("a" + k, 60);
                                System.out.println(System.currentTimeMillis() + "--" + Thread.currentThread().getName()
                                        + "--key:" + ("a" + k) + "不存在,设置值为: " + Thread.currentThread().getName());
                                try {
                                    // Thread.sleep((long) (Math.random()*1000));
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            } else {
                                System.out.println(Thread.currentThread().getName() + "--key:" + ("a" + k) + "存在,值为: " + v);
                            }
    //                        }
                            jedis.close();
                        }
                    }
                }).start();
            }
        }
        /*    不加锁的运行结果: 可以看到一个键比如 a0被赋值了很多次,说明有线程安全问题(原因是getKey 和 setKey 的方法不同步),
         *     如果在单服务环境可以用synchronized来解决,但是如果分布式多节点服务,synchronized 就无效了
         * 
         * 1556503338616--Thread-2--key:a0不存在,设置值为: Thread-2
         * 1556503338616--Thread-1--key:a0不存在,设置值为: Thread-1
         * 1556503338616--Thread-0--key:a0不存在,设置值为: Thread-0
         * 1556503338622--Thread-2--key:a1不存在,设置值为: Thread-2 Thread-0--key:a1存在,值为:
         * Thread-2 1556503338622--Thread-1--key:a1不存在,设置值为: Thread-1
         * 1556503338627--Thread-2--key:a2不存在,设置值为: Thread-2
         * 1556503338627--Thread-0--key:a2不存在,设置值为: Thread-0
         * 1556503338628--Thread-1--key:a2不存在,设置值为: Thread-1
         * 1556503338634--Thread-2--key:a3不存在,设置值为: Thread-2
         * 1556503338634--Thread-0--key:a3不存在,设置值为: Thread-0
         * 1556503338634--Thread-1--key:a3不存在,设置值为: Thread-1
         * 1556503338644--Thread-2--key:a4不存在,设置值为: Thread-2
         */
    
        
        
        public static void main(String[] args) {
            //获取redisson
            Config config = new Config();
            config.useSingleServer().setAddress("redis://localhost:6379");
            RedissonClient redisson = Redisson.create(config);
            //获取锁
            RLock lock = redisson.getLock("mylock");
    
            for (int i = 0; i < 3; i++) {
    //            final int k = i;
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        for (int j = 0; j < 10; j++) {
                            int k = j;
                            // 连接本地的 Redis 服务
    //                        Jedis jedis = new Jedis("localhost");
                            // 创建连接池对象
                            JedisPool jedisPool = new JedisPool("127.0.0.1", 6379);
                            try {
                                //加分布式锁
                                lock.lock();
                                // 从连接池中获取一个jedis对象
                                Jedis jedis = jedisPool.getResource();
                                if (!jedis.exists("a" + k)) {
                                    jedis.set("a" + k, Thread.currentThread().getName());
                                    jedis.expire("a" + k, 60);
                                    System.out.println(System.currentTimeMillis() + "--" + Thread.currentThread().getName()
                                            + "--key:" + ("a" + k) + "不存在,设置值为: " + Thread.currentThread().getName());
                                    try {
                                        // Thread.sleep((long) (Math.random()*1000));
                                    } catch (Exception e) {
                                        e.printStackTrace();
                                    }
                                } else {
                                    System.out.println(Thread.currentThread().getName() + "--key:" + ("a" + k) + "存在,值为: "
                                            + jedis.get("a" + k));
                                }
                                jedis.close();
                            } finally {
                                //释放分布式锁
                                lock.unlock();
                            }
                        }
                    }
                }).start();
            }
        }
        
        /* 加上分布式锁后的运行结果:  可以看到每一个键比如 a0只被赋值了一次,说明没有线程安全问题了
         * (在这个例子中,redisson 连接redis只是用来做分布式锁,真正的业务中的redis操作用的还是其他连接方式,比如 jedisPool 等)
         * 
         * 1556505103008--Thread-4--key:a0不存在,设置值为: Thread-4 Thread-2--key:a0存在,值为:
         * Thread-4 Thread-3--key:a0存在,值为: Thread-4
         * 1556505103035--Thread-4--key:a1不存在,设置值为: Thread-4 Thread-2--key:a1存在,值为:
         * Thread-4 Thread-3--key:a1存在,值为: Thread-4
         * 1556505103058--Thread-4--key:a2不存在,设置值为: Thread-4 Thread-2--key:a2存在,值为:
         * Thread-4 Thread-3--key:a2存在,值为: Thread-4
         * 1556505103080--Thread-4--key:a3不存在,设置值为: Thread-4 Thread-2--key:a3存在,值为:
         * Thread-4 Thread-3--key:a3存在,值为: Thread-4
         * 1556505103100--Thread-4--key:a4不存在,设置值为: Thread-4 Thread-2--key:a4存在,值为:
         * Thread-4 Thread-3--key:a4存在,值为: Thread-4
         * 1556505103126--Thread-4--key:a5不存在,设置值为: Thread-4 Thread-2--key:a5存在,值为:
         * Thread-4 Thread-3--key:a5存在,值为: Thread-4
         * 1556505103146--Thread-2--key:a6不存在,设置值为: Thread-2 Thread-4--key:a6存在,值为:
         * Thread-2 Thread-3--key:a6存在,值为: Thread-2
         * 1556505103165--Thread-4--key:a7不存在,设置值为: Thread-4 Thread-2--key:a7存在,值为:
         * Thread-4 Thread-3--key:a7存在,值为: Thread-4
         * 1556505103186--Thread-4--key:a8不存在,设置值为: Thread-4 Thread-2--key:a8存在,值为:
         * Thread-4 1556505103197--Thread-4--key:a9不存在,设置值为: Thread-4
         * Thread-2--key:a9存在,值为: Thread-4 Thread-3--key:a8存在,值为: Thread-4
         * Thread-3--key:a9存在,值为: Thread-4
         */
    
    }

    ---------------------------------------------------

    注意:

    如果不是想用分布式锁解决其他业务逻辑问题,而只是为了解决本文标题说的向redis中存入取出值(如果存在就取出,如果不存在就存入)的问题,那么完全可以用下面的方法来实现

     其原理就是下面这个方法:
    //     jedis.set("key", "value", "nx", "ex", 50L); //第一个参数:key,第二个参数:value,第三、四个参数固定写法,第五个参数:超时毫秒值
    //    上面这个方法其实就是redis的 setnx 和  expire 组合在一起的原子指令 (据说其是Redis2.8版本增加的新特性,但是我在2.4版本居然也能用)
        public static void main(String[] args) {
            for (int i = 0; i < 3; i++) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        for (int j = 0; j < 10; j++) {
                            int k = j;
                            // 连接本地的 Redis 服务
    //                        Jedis jedis = new Jedis("localhost");
                            // 创建连接池对象
                            JedisPool jedisPool = new JedisPool("127.0.0.1", 6379);
                            // 从连接池中获取一个jedis对象
                            Jedis jedis = jedisPool.getResource();
                            String setResult = jedis.set("a" + k, Thread.currentThread().getName(), "nx", "ex", 50L);
                            if (setResult == null) {
                                // 说明已经存在,设置值失败
                                System.out.println(Thread.currentThread().getName() + "--key:" + ("a" + k) + "存在,值为: "
                                        + jedis.get("a" + k));
                            } else {
                                // 说明设置值成功
                                System.out.println(System.currentTimeMillis() + "--" + Thread.currentThread().getName()
                                        + "--key:" + ("a" + k) + "不存在,设置值为: " + Thread.currentThread().getName());
                            }
                            jedis.close();
                        }
                    }
                }).start();
            }
        }
        
    //    运行结果: 说明这是没有问题的
    //    也就是说,如果不是想用分布式锁解决其他业务逻辑问题,而只是为了解决向redis中存入取出值(如果存在就取出,如果不存在就存入)的问题,那么完全可以用上面的方法来实现
    //    其原理就是下面这个方法:
    //     jedis.set("key", "value", "nx", "ex", 50L); //第一个参数:key,第二个参数:value,第三、四个参数固定写法,第五个参数:超时毫秒值
    //    上面这个方法其实就是redis的 setnx 和  expire 组合在一起的原子指令 (据说其是Redis2.8版本增加的新特性,但是我在2.4版本居然也能用)
    //    1556588977532--Thread-0--key:a0不存在,设置值为: Thread-0
    //    Thread-1--key:a0存在,值为: Thread-0
    //    Thread-2--key:a0存在,值为: Thread-0
    //    1556588977535--Thread-0--key:a1不存在,设置值为: Thread-0
    //    Thread-2--key:a1存在,值为: Thread-0
    //    Thread-1--key:a1存在,值为: Thread-0
    //    1556588977538--Thread-0--key:a2不存在,设置值为: Thread-0
    //    Thread-2--key:a2存在,值为: Thread-0
    //    Thread-1--key:a2存在,值为: Thread-0
    //    1556588977541--Thread-0--key:a3不存在,设置值为: Thread-0
    //    1556588977545--Thread-0--key:a4不存在,设置值为: Thread-0
    //    Thread-1--key:a3存在,值为: Thread-0
    //    Thread-2--key:a3存在,值为: Thread-0
    //    Thread-2--key:a4存在,值为: Thread-0
    //    1556588977553--Thread-0--key:a5不存在,设置值为: Thread-0
    //    Thread-1--key:a4存在,值为: Thread-0
    //    1556588977558--Thread-0--key:a6不存在,设置值为: Thread-0
    //    1556588977562--Thread-0--key:a7不存在,设置值为: Thread-0
    //    Thread-1--key:a5存在,值为: Thread-0
    //    Thread-2--key:a5存在,值为: Thread-0
    //    1556588977566--Thread-0--key:a8不存在,设置值为: Thread-0
    //    Thread-2--key:a6存在,值为: Thread-0
    //    Thread-1--key:a6存在,值为: Thread-0
    //    1556588977578--Thread-0--key:a9不存在,设置值为: Thread-0
    //    Thread-2--key:a7存在,值为: Thread-0
    //    Thread-1--key:a7存在,值为: Thread-0
    //    Thread-2--key:a8存在,值为: Thread-0
    //    Thread-1--key:a8存在,值为: Thread-0
    //    Thread-2--key:a9存在,值为: Thread-0
    //    Thread-1--key:a9存在,值为: Thread-0
  • 相关阅读:
    docker安装
    win8换win7的操作方法
    java数组实现队列
    springMVC源码学习之获取参数名
    SpringMVC源码学习之request处理流程
    LeetCode 231. Power of Two
    LeetCode 202. Happy Number
    LeetCode 171. Excel Sheet Column Number
    Eclipse 保存代码时,不自动换行设置
    LeetCode 141. Linked List Cycle
  • 原文地址:https://www.cnblogs.com/libin6505/p/10789256.html
Copyright © 2020-2023  润新知