关于redisson锁续期的疑问

从新的3.x版本后的redisson的源码中可以找到为锁续期创建的定时任务,但是在老的1.2.1中并没有找到定时任务的创建,所以redisson的锁自动续期能力是后来版本引入的嘛?还是策略有所变化。

3.11版本

  private void scheduleExpirationRenewal(long threadId) {
    RedissonLock.ExpirationEntry entry = new RedissonLock.ExpirationEntry();
    RedissonLock.ExpirationEntry oldEntry = (RedissonLock.ExpirationEntry)EXPIRATION_RENEWAL_MAP.putIfAbsent(this.getEntryName(), entry);
    if (oldEntry != null) {
      oldEntry.addThreadId(threadId);
    } else {
      entry.addThreadId(threadId);
      this.renewExpiration();
    }

  }



private void renewExpiration() {
    RedissonLock.ExpirationEntry ee = (RedissonLock.ExpirationEntry)EXPIRATION_RENEWAL_MAP.get(this.getEntryName());
    if (ee != null) {
      Timeout task = this.commandExecutor.getConnectionManager().newTimeout(new TimerTask() {
        public void run(Timeout timeout) throws Exception {
          RedissonLock.ExpirationEntry ent = (RedissonLock.ExpirationEntry)RedissonLock.EXPIRATION_RENEWAL_MAP.get(RedissonLock.this.getEntryName());
          if (ent != null) {
            Long threadId = ent.getFirstThreadId();
            if (threadId != null) {
              RFuture<Boolean> future = RedissonLock.this.renewExpirationAsync(threadId);
              future.onComplete((res, e) -> {
                if (e != null) {
                  RedissonLock.log.error("Can't update lock " + RedissonLock.this.getName() + " expiration", e);
                } else {
                  if (res) {
                    RedissonLock.this.renewExpiration();
                  }

                }
              });
            }
          }
        }
      }, this.internalLockLeaseTime / 3L, TimeUnit.MILLISECONDS);
      ee.setTimeout(task);
    }
  }

1.2.1版本,RedissonLock的全部源码

package org.redisson;

import com.lambdaworks.redis.RedisAsyncConnection;
import com.lambdaworks.redis.RedisConnection;
import com.lambdaworks.redis.pubsub.RedisPubSubAdapter;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import java.io.Serializable;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import org.redisson.async.ResultOperation;
import org.redisson.async.SyncOperation;
import org.redisson.connection.ConnectionManager;
import org.redisson.core.RLock;

public class RedissonLock extends RedissonObject implements RLock {
  private final UUID id;
  private static final Integer unlockMessage = 0;
  private static final ConcurrentMap<String, RedissonLockEntry> ENTRIES = new ConcurrentHashMap();

  protected RedissonLock(ConnectionManager connectionManager, String name, UUID id) {
    super(connectionManager, name);
    this.id = id;
  }

  private void unsubscribe() {
    RedissonLockEntry entry;
    RedissonLockEntry newEntry;
    do {
      entry = (RedissonLockEntry)ENTRIES.get(this.getEntryName());
      if (entry == null) {
        return;
      }

      newEntry = new RedissonLockEntry(entry);
      newEntry.release();
    } while(!ENTRIES.replace(this.getEntryName(), entry, newEntry));

    if (newEntry.isFree() && ENTRIES.remove(this.getEntryName(), newEntry)) {
      synchronized(ENTRIES) {
        if (!ENTRIES.containsKey(this.getEntryName())) {
          this.connectionManager.unsubscribe(this.getChannelName());
        }
      }
    }

  }

  private String getEntryName() {
    return this.id + ":" + this.getName();
  }

  private Promise<Boolean> aquire() {
    RedissonLockEntry entry;
    RedissonLockEntry newEntry;
    do {
      entry = (RedissonLockEntry)ENTRIES.get(this.getEntryName());
      if (entry == null) {
        return null;
      }

      newEntry = new RedissonLockEntry(entry);
      newEntry.aquire();
    } while(!ENTRIES.replace(this.getEntryName(), entry, newEntry));

    return newEntry.getPromise();
  }

  private Future<Boolean> subscribe() {
    Promise<Boolean> promise = this.aquire();
    if (promise != null) {
      return promise;
    } else {
      Promise<Boolean> newPromise = this.newPromise();
      final RedissonLockEntry value = new RedissonLockEntry(newPromise);
      value.aquire();
      RedissonLockEntry oldValue = (RedissonLockEntry)ENTRIES.putIfAbsent(this.getEntryName(), value);
      if (oldValue != null) {
        Promise<Boolean> oldPromise = this.aquire();
        return (Future)(oldPromise == null ? this.subscribe() : oldPromise);
      } else {
        RedisPubSubAdapter<Object> listener = new RedisPubSubAdapter<Object>() {
          public void subscribed(String channel, long count) {
            if (RedissonLock.this.getChannelName().equals(channel) && !value.getPromise().isSuccess()) {
              value.getPromise().setSuccess(true);
            }

          }

          public void message(String channel, Object message) {
            if (message.equals(RedissonLock.unlockMessage) && RedissonLock.this.getChannelName().equals(channel)) {
              value.getLatch().release();
            }

          }
        };
        synchronized(ENTRIES) {
          this.connectionManager.subscribe(listener, this.getChannelName());
          return newPromise;
        }
      }
    }
  }

  private String getChannelName() {
    return "redisson__lock__channel__{" + this.getName() + "}";
  }

  public void lock() {
    try {
      this.lockInterruptibly();
    } catch (InterruptedException var2) {
      Thread.currentThread().interrupt();
    }
  }

  public void lock(long leaseTime, TimeUnit unit) {
    try {
      this.lockInterruptibly(leaseTime, unit);
    } catch (InterruptedException var5) {
      Thread.currentThread().interrupt();
    }
  }

  public void lockInterruptibly() throws InterruptedException {
    this.lockInterruptibly(-1L, (TimeUnit)null);
  }

   // 在这里找不到锁续期的代码
  public void lockInterruptibly(long leaseTime, TimeUnit unit) throws InterruptedException {
    Long ttl;
    if (leaseTime != -1L) {
      ttl = this.tryLockInner(leaseTime, unit);
    } else {
      ttl = this.tryLockInner();
    }

    if (ttl != null) {
       // 这个方法实际的作用看不太懂,比较复杂
      this.subscribe().awaitUninterruptibly();

      try {
        while(true) {
          if (leaseTime != -1L) {
            ttl = this.tryLockInner(leaseTime, unit);
          } else {
            ttl = this.tryLockInner();
          }

          if (ttl == null) {
            return;
          }

          RedissonLockEntry entry = (RedissonLockEntry)ENTRIES.get(this.getEntryName());
          if (ttl >= 0L) {
            entry.getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);
          } else {
            entry.getLatch().acquire();
          }
        }
      } finally {
        this.unsubscribe();
      }
    }
  }

  public boolean tryLock() {
    return this.tryLockInner() == null;
  }

  private Long tryLockInner() {
    final RedissonLock.LockValue currentLock = new RedissonLock.LockValue(this.id, Thread.currentThread().getId());
    currentLock.incCounter();
    return (Long)this.connectionManager.write(this.getName(), new SyncOperation<RedissonLock.LockValue, Long>() {
      public Long execute(RedisConnection<Object, RedissonLock.LockValue> connection) {
        Boolean res = connection.setnx(RedissonLock.this.getName(), currentLock);
        if (!res) {
          connection.watch(new Object[]{RedissonLock.this.getName()});
          RedissonLock.LockValue lock = (RedissonLock.LockValue)connection.get(RedissonLock.this.getName());
          if (lock != null && lock.equals(currentLock)) {
            lock.incCounter();
            connection.multi();
            connection.set(RedissonLock.this.getName(), lock);
            if (connection.exec().size() == 1) {
              return null;
            }
          }

          connection.unwatch();
          Long ttl = connection.pttl(RedissonLock.this.getName());
          return ttl;
        } else {
          return null;
        }
      }
    });
  }

  private Long tryLockInner(final long leaseTime, final TimeUnit unit) {
    final RedissonLock.LockValue currentLock = new RedissonLock.LockValue(this.id, Thread.currentThread().getId());
    currentLock.incCounter();
    return (Long)this.connectionManager.write(this.getName(), new SyncOperation<Object, Long>() {
      public Long execute(RedisConnection<Object, Object> connection) {
        long time = unit.toMillis(leaseTime);
        String res = connection.setexnx(RedissonLock.this.getName(), currentLock, time);
        if ("OK".equals(res)) {
          return null;
        } else {
          connection.watch(new Object[]{RedissonLock.this.getName()});
          RedissonLock.LockValue lock = (RedissonLock.LockValue)connection.get(RedissonLock.this.getName());
          if (lock != null && lock.equals(currentLock)) {
            lock.incCounter();
            connection.multi();
            connection.psetex(RedissonLock.this.getName(), time, lock);
            if (connection.exec().size() == 1) {
              return null;
            }
          }

          connection.unwatch();
          Long ttl = connection.pttl(RedissonLock.this.getName());
          return ttl;
        }
      }
    });
  }

  public boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException {
    long time = unit.toMillis(waitTime);
    Long ttl;
    if (leaseTime != -1L) {
      ttl = this.tryLockInner(leaseTime, unit);
    } else {
      ttl = this.tryLockInner();
    }

    if (ttl == null) {
      return true;
    } else if (!this.subscribe().awaitUninterruptibly(time, TimeUnit.MILLISECONDS)) {
      return false;
    } else {
      try {
        while(true) {
          if (leaseTime != -1L) {
            ttl = this.tryLockInner(leaseTime, unit);
          } else {
            ttl = this.tryLockInner();
          }

          boolean var17;
          if (ttl == null) {
            var17 = true;
            return var17;
          }

          if (time <= 0L) {
            var17 = false;
            return var17;
          }

          long current = System.currentTimeMillis();
          RedissonLockEntry entry = (RedissonLockEntry)ENTRIES.get(this.getEntryName());
          if (ttl >= 0L && ttl < time) {
            entry.getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);
          } else {
            entry.getLatch().tryAcquire(time, TimeUnit.MILLISECONDS);
          }

          long elapsed = System.currentTimeMillis() - current;
          time -= elapsed;
        }
      } finally {
        this.unsubscribe();
      }
    }
  }

  public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
    return this.tryLock(time, -1L, unit);
  }

  public void unlock() {
    this.connectionManager.write(this.getName(), new SyncOperation<Object, Void>() {
      public Void execute(RedisConnection<Object, Object> connection) {
        RedissonLock.LockValue lock = (RedissonLock.LockValue)connection.get(RedissonLock.this.getName());
        if (lock != null) {
          RedissonLock.LockValue currentLock = new RedissonLock.LockValue(RedissonLock.this.id, Thread.currentThread().getId());
          if (!lock.equals(currentLock)) {
            throw new IllegalMonitorStateException("Attempt to unlock lock, not locked by current id: " + RedissonLock.this.id + " thread-id: " + Thread.currentThread().getId());
          }

          if (lock.getCounter() > 1) {
            lock.decCounter();
            connection.set(RedissonLock.this.getName(), lock);
          } else {
            RedissonLock.this.unlock(connection);
          }
        }

        return null;
      }
    });
  }

  private void unlock(RedisConnection<Object, Object> connection) {
    for(int counter = 0; counter < 5; ++counter) {
      connection.multi();
      connection.del(new Object[]{this.getName()});
      connection.publish(this.getChannelName(), unlockMessage);
      List<Object> res = connection.exec();
      if (res.size() == 2) {
        return;
      }
    }

    throw new IllegalStateException("Can't unlock lock after 5 attempts. Current id: " + this.id + " thread-id: " + Thread.currentThread().getId());
  }

  public Condition newCondition() {
    throw new UnsupportedOperationException();
  }

  public void forceUnlock() {
    this.connectionManager.write(this.getName(), new SyncOperation<Object, Void>() {
      public Void execute(RedisConnection<Object, Object> connection) {
        RedissonLock.this.unlock(connection);
        return null;
      }
    });
  }

  public boolean isLocked() {
    return this.getCurrentLock() != null;
  }

  private RedissonLock.LockValue getCurrentLock() {
    RedissonLock.LockValue lock = (RedissonLock.LockValue)this.connectionManager.read(this.getName(), new ResultOperation<RedissonLock.LockValue, RedissonLock.LockValue>() {
      protected Future<RedissonLock.LockValue> execute(RedisAsyncConnection<Object, RedissonLock.LockValue> async) {
        return async.get(RedissonLock.this.getName());
      }
    });
    return lock;
  }

  public boolean isHeldByCurrentThread() {
    RedissonLock.LockValue lock = this.getCurrentLock();
    RedissonLock.LockValue currentLock = new RedissonLock.LockValue(this.id, Thread.currentThread().getId());
    return lock != null && lock.equals(currentLock);
  }

  public int getHoldCount() {
    RedissonLock.LockValue lock = this.getCurrentLock();
    RedissonLock.LockValue currentLock = new RedissonLock.LockValue(this.id, Thread.currentThread().getId());
    return lock != null && lock.equals(currentLock) ? lock.getCounter() : 0;
  }

  public void delete() {
    this.forceUnlock();
  }

  public static class LockValue implements Serializable {
    private static final long serialVersionUID = -8895632286065689476L;
    private UUID id;
    private Long threadId;
    private int counter;

    public LockValue() {
    }

    public LockValue(UUID id, Long threadId) {
      this.id = id;
      this.threadId = threadId;
    }

    public void decCounter() {
      --this.counter;
    }

    public void incCounter() {
      ++this.counter;
    }

    public int getCounter() {
      return this.counter;
    }

    public int hashCode() {
      int prime = true;
      int result = 1;
      int result = 31 * result + (this.id == null ? 0 : this.id.hashCode());
      result = 31 * result + (this.threadId == null ? 0 : this.threadId.hashCode());
      return result;
    }

    public boolean equals(Object obj) {
      if (this == obj) {
        return true;
      } else if (obj == null) {
        return false;
      } else if (this.getClass() != obj.getClass()) {
        return false;
      } else {
        RedissonLock.LockValue other = (RedissonLock.LockValue)obj;
        if (this.id == null) {
          if (other.id != null) {
            return false;
          }
        } else if (!this.id.equals(other.id)) {
          return false;
        }

        if (this.threadId == null) {
          if (other.threadId != null) {
            return false;
          }
        } else if (!this.threadId.equals(other.threadId)) {
          return false;
        }

        return true;
      }
    }
  }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值