## 简介

在分布式环境下，需要独占(锁定)某个资源的时候，需要用到分布式锁。



创建锁的方式：

- `DLock.create`： 不可重入锁，当前线程不可重入。
- `DLock.createReentrant`：可重入锁，当前线程可重入。



当拥有某个锁的微服务节点因某些原因(如网络)失联时，该锁仍生效，此服务节点在服务注册中心被移除后，该锁自动失效。



## 用法

**示例**

```java
import kd.bos.dlock.DLock;

DLock lock = DLock.create("fi/gl/N20180503-8808", "凭证N20180503-8808");
// 一直等待直到获得锁
lock.lock();
try {
	// 获取锁信息：
    // {key: fi/gl/N20180503-8808, desc: 凭证N20180503-8808, owner: 163388da76b0046, waitingLocks: 0, createTime: 2018-05-08 11:35:50.087}
	System.out.println(DLock.getLockInfo("fi/gl/N20180503-8808"));
    
    // 获取所有锁信息
	// System.out.println(DLock.getAllLockInfo());	
	// ...
} finally {
	lock.unlock();
}
```

注意，获得锁后务必确保最终进行了解锁 (unlock，通常在finally里)。



**锁模式**

在运行期可以根据业务场景，指定某个锁的运行模式。

不同锁的模式用于区分服务节点出现异常无法连接时，自动解锁的时机。

- 稳定模式：拥有锁的服务节点断开连接且在注册中心被移除后，锁自动失效。
- 性能模式：拥有锁的服务节点断开连接后，锁自动失效。

```java
// 当前锁模式为系统设置的默认模式，默认模式为稳定模式(可配)。
DLock lock = DLock.create("xxx");

// 切换为稳定模式
lock.fastMode();

// 切换为性能模式
lock.stableMode();
```

模式的切换在lock()、tryLock()之前设置才有效。



**解锁**

```java
// 用lock对象的解锁方法
lock.unlock();

/**
 * 强制解锁
 */
DLock.forceUnlock(String... keys);

/**
 * 强制清除锁(包括在等待的)
 */
DLock.forceClear(String... keys);
```



**手工解锁**

稳定模式下，若微服务节点停止后，其原来用的锁一直占用，则是因为微服务节点在注册中心还存在(本应移除的)。可以进入monitor，手工清除：点开分布式锁，找到所在的账套ID对应的锁，点击"clear"。



## 锁接口

```java
public interface DLock extends AutoCloseable{

	/**
	 * 获取锁，一直等待，直到获取。
	 */
	void lock();

	/**
	 * 尝试获取锁，不等待，获取到返回true(无锁竞争的情况下必为true)，否则返回false。
	 */
	boolean tryLock();

	/**
	 * 尝试获取锁，在timeoutMillis毫秒内获取到，返回true，否则返回false。
	 */
	boolean tryLock(long timeoutMillis);

	/**
	 * 释放锁
	 */
	void unlock();
	
	/**
	 * 等同unlock
	 */
	void close();

	/**
	 * 快速模式。
	 */
	DLock fastMode();

	/**
	 * 稳定模式。
	 */
	DLock stableMode();
	
	
	//////////////////////////////// static method ///////////////////////////////////

	/**
	 * 分布式锁对象，不可重入。
	 */
	static DLock create(String key);

	static DLock create(String key, String desc);

	/**
	 * 分布式锁对象，可重入(仅在本jvm范围内)。
	 */
	static DLock createReentrant(String key);

	static DLock createReentrant(String key, String desc);

	/**
	 * 获取所有锁信息
	 */
	static Map<String, DLockInfo> getAllLockInfo();

	/**
	 * 获取key对应的锁信息，不存在则返回null。
	 */
	static DLockInfo getLockInfo(String key);

	/**
	 * 强制解锁
	 */
	static void forceUnlock(String... keys);

	/**
	 * 强制清除锁(包括在等待的)
	 */
	static void forceClear(String... keys);

}
```



## 服务配置

分布式锁服务的配置如下，由配置中心在启动前设置好。

| 版本选择                                        | 默认模式                                   | 说明                                                         |
| ----------------------------------------------- | ------------------------------------------ | ------------------------------------------------------------ |
| **Zookeeper版**<br/>DLock.type=zookeeper (默认) | **稳定模式**DLock.performance=false (默认) | 锁正在使用中，服务器停止，则锁不会立即释放，只有等到服务节点在zookeeper注册中心消失后才会失效。(下次申请该锁时检测，若微服务节点已经不存在则释放该锁并获取锁)<br/>每个锁在zk上对应一个幻象节点+一个持久化节点。 |
|                                                 | 性能模式DLock.performance=true             | 锁正在使用中，服务器停止，则锁自动释放。<br/>每个锁在zk上对应一个幻象节点。 |
| Redis版<br/>DLock.type=redis                    |                                            | 性能是zk版的8~10倍，高并发下占用redis服务资源大。若启用该版本，建议单独配置服务器。<br/>指定redis:  redis.dlock=redis服务地址 |

