首页 > 数据库 > Redis > 正文

redis锁机制介绍与实例

2020-10-28 21:31:16
字体:
来源:转载
供稿:网友

1 悲观锁

执行操作前假设当前的操作肯定(或有很大几率)会被打断(悲观)。基于这个假设,我们在做操作前就会把相关资源锁定,不允许自己执行期间有其他操作干扰。

Redis不支持悲观锁。Redis作为缓存服务器使用时,以读操作为主,很少写操作,相应的操作被打断的几率较少。不采用悲观锁是为了防止降低性能。

2 乐观锁

执行操作前假设当前操作不会被打断(乐观)。基于这个假设,我们在做操作前不会锁定资源,万一发生了其他操作的干扰,那么本次操作将被放弃。

3. Redis中的锁策略

Redis采用了乐观锁策略(通过watch操作)。乐观锁支持读操作,适用于多读少写的情况!
在事务中,可以通过watch命令来加锁;使用 UNWATCH可以取消加锁;
如果在事务之前,执行了WATCH(加锁),那么执行EXEC 命令或 DISCARD 命令后,锁对自动释放,即不需要再执行 UNWATCH 了

例子

redis锁工具类

package com.fly.lock;import redis.clients.jedis.Jedis;import redis.clients.jedis.JedisPool;import redis.clients.jedis.JedisPoolConfig;public class RedisLock {  //初始化redis池  private static JedisPoolConfig config;  private static JedisPool pool;  static {    config = new JedisPoolConfig();    config.setMaxTotal(30);    config.setMaxIdle(10);    pool = new JedisPool(config, "192.168.233.200", 6379);  }  /**   * 给target上锁   * @param target   **/  public static void lock(Object target) {    //获取jedis    Jedis jedis = pool.getResource();    //result接收setnx的返回值,初始值为0    Long result= 0L;    while (result < 1) {      //如果target在redis中已经存在,则返回0;否则,在redis中设置target键值对,并返回1      result = jedis.setnx(target.getClass().getName() + target.hashCode(), Thread.currentThread().getName());    }    jedis.close();  }  /**   * 给target解锁   * @param target   **/  public static void unLock(Object target) {    Jedis jedis = pool.getResource();    //删除redis中target对象的键值对    Long del = jedis.del(target.getClass().getName() + target.hashCode());    jedis.close();  }  /**   * 尝试给target上锁,如果锁成功返回true,如果锁失败返回false   * @param target   * @return   **/  public static boolean tryLock(Object target) {    Jedis jedis = pool.getResource();    Long row = jedis.setnx(target.getClass().getName() + target.hashCode(), "true");    jedis.close();    if (row > 0) {      return true;    }    return false;  }}

测试类

package com.fly.test;import com.fly.lock.RedisLock;class Task {  public void doTask() {    //上锁    RedisLock.lock(this);    System.out.println("当前线程: " + Thread.currentThread().getName());    System.out.println("开始执行: " + this.hashCode());    try {      System.out.println("doing...");      Thread.sleep(2000);    } catch (InterruptedException e) {      e.printStackTrace();    }    System.out.println("完成: " + this.hashCode());    //解锁    RedisLock.unLock(this);  }}public class Demo {  public static void main(String[] args) {    Task task = new Task();    Thread[] threads = new Thread[5];    for (Thread thread : threads) {      thread = new Thread(()->{        task.doTask();      });      thread.start();    }  }}

输出结果:

----------------------------------------------
当前线程: Thread-0
开始执行: 2081499965
doing...
完成: 2081499965
----------------------------------------------
当前线程: Thread-2
开始执行: 2081499965
doing...
完成: 2081499965
----------------------------------------------
当前线程: Thread-1
开始执行: 2081499965
doing...
完成: 2081499965
----------------------------------------------
当前线程: Thread-4
开始执行: 2081499965
doing...
完成: 2081499965
----------------------------------------------
当前线程: Thread-3
开始执行: 2081499965
doing...
完成: 2081499965

去掉redis锁后,执行结果:

----------------------------------------------
----------------------------------------------
当前线程: Thread-2
开始执行: 1926683415
----------------------------------------------
当前线程: Thread-1
doing...
当前线程: Thread-0
----------------------------------------------
当前线程: Thread-3
开始执行: 1926683415
doing...
开始执行: 1926683415
doing...
----------------------------------------------
开始执行: 1926683415
doing...
当前线程: Thread-4
开始执行: 1926683415
doing...
完成: 1926683415
完成: 1926683415
完成: 1926683415
完成: 1926683415
完成: 1926683415

Process finished with exit code 0

利用redis这个性质,可以实现分布式锁,当然设计一定复杂一些!

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对武林网的支持。如果你想了解更多相关内容请查看下面相关链接

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表