從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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM