1. 文章导读
随着互联网的兴起,应用的单服务器部署已无法满足日益增长的用户需求,此时云服务+分布式技术应用而生,解决了应用弹性伸缩的问题。
问题来了,分布式不同于单机,在单机应用下可以使用Java的并发编程API实现对共享资源的控制,而在分布式应用系统环境则需要借助Curator+Zookeeper来实现。
本文基于Curator+Zookeeper实现各种分布式锁,以实现分布式环境下对有限共享资源的并发访问。
2. 共享非可重入锁
2.1 概念
何为共享锁,所有分布式中的应用进程之间共享的锁,确保每次只能有一个进程获取到锁,其它应用需要等待持有者释放后,才能获取到锁。
2.2 源码解读
- 公共代码片段
package com.example.curatorsimpledemo.recipes;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.locks.InterProcessLock;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.framework.recipes.locks.InterProcessSemaphoreMutex;
import org.apache.curator.framework.recipes.locks.InterProcessReadWriteLock;
import org.apache.curator.framework.recipes.locks.InterProcessMultiLock;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.curator.utils.CloseableUtils;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
@RunWith(SpringJUnit4ClassRunner.class)
public class DistributedLockDemo {
// ZooKeeper 锁节点路径, 分布式锁的相关操作都是在这个节点上进行
private final String lockPath = "/distri-lock";
// ZooKeeper 服务地址, 单机格式为:(127.0.0.1:2181), 集群格式为:(127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183)
private String connectString;
// Curator 客户端重试策略
private RetryPolicy retry;
// Curator 客户端对象
private CuratorFramework client;
// client2 用户模拟其他客户端
private CuratorFramework client2;
// 初始化资源
@Before
public void init() throws Exception {
// 设置 ZooKeeper 服务地址为本机的 2181 端口
connectString = "192.168.206.100:2181";
// 重试策略
// 初始休眠时间为 1000ms, 最大重试次数为 3 retry = new ExponentialBackoffRetry(1000, 3);
// 创建一个客户端, 60000(ms)为 session 超时时间, 15000(ms)为链接超时时间
client = CuratorFrameworkFactory.newClient(connectString, 60000, 15000, retry);
client2 = CuratorFrameworkFactory.newClient(connectString, 60000, 15000, retry);
// 创建会话
client.start();
client2.start();
}
// 释放资源
@After
public void close() {
CloseableUtils.closeQuietly(client);
}
}
- 共享非可重入锁的测试用例
@Test
public void sharedLock() throws Exception {
// 创建共享锁 模拟第1个进程
InterProcessLock lock = new InterProcessSemaphoreMutex(client, lockPath);
// lock2 用于模拟分布式环境中的其它进程
InterProcessLock lock2 = new InterProcessSemaphoreMutex(client2, lockPath);
// 直接获取锁对象
lock.acquire();
// 测试是否可以重入
/** 超时获取锁对象的方法 boolean acquire(long var1, TimeUnit var3) 第一个参数为时间, 第二个参数为时间单位。 给获取所对象设置个超时时间,超过指定时间没有获得锁则返回false。
因为锁已经被获取, 所以返回 false。
**/
Assert.assertFalse(lock.acquire(2, TimeUnit.SECONDS));
// 继续测试进程2能否获取锁, 同样lockPath已经被锁lock锁住,进程2没法再用lock2去加锁。
Assert.assertFalse(lock2.acquire(2, TimeUnit.SECONDS));
// 进程1释放lockPath的锁lock
lock.release();
// lock2 尝试获取锁成功, 因为锁已经被释放
Assert.assertTrue(lock2.acquire(2, TimeUnit.

最低0.47元/天 解锁文章
1453





