文章目录
- memcached分布式锁
- 实现原理:
- 优缺点
- 开发准备
- 安装memcached服务端
- 安装jar到maven本地仓库
- 代码开发
- 初始化Memcached客户端
- 锁相关操作核心代码
- 本地运行效果
- docker运行效果
memcached分布式锁
实现原理:
memcached带有add函数,利用add函数的特性即可实现分布式锁。
add和set的区别在于:如果多线程并发set,则每个set都会成功,但最后存储的值以最后的set的线程为准。而add的话则相反,add会添加第一个到达的值,并返回true,后续的添加则都会返回false。
利用该点即可很轻松地实现分布式锁。
优缺点
优点:并发高效。
缺点:
(1)memcached采用列入LRU置换策略,所以如果内存不够,可能导致缓存中的锁信息丢失。
(2)memcached无法持久化,一旦重启,将导致信息丢失。
开发准备
安装memcached服务端
为方便起见,已经将memcached服务器端程序上传到下面的目录,使用时只需要双击运行就好!
安装jar到maven本地仓库
开发的时候有的同学可能会遇到下面jar无法下载的情况
<!-- mvn install:install-file -Dfile="java_memcached-release_2.6.6.jar" -DgroupId=com.danga -DartifactId=java-memcached -Dversion="2.6.6" -Dpackaging=jar -->
<dependency>
<groupId>com.danga</groupId>
<artifactId>java-memcached</artifactId>
<version>2.6.6</version>
</dependency>
在java-memcached-2.6.6.jar同级目录运行
mvn install:install-file -Dfile="java_memcached-release_2.6.6.jar" -DgroupId=com.danga -DartifactId=java-memcached -Dversion="2.6.6" -Dpackaging=jar
代码开发
初始化Memcached客户端
@Component
public class MemcachedLockClient
{
@Value("${memcached.serverUrl:127.0.0.1:11211}")
private String server;
/**
* 构建缓存客户端
*/
private MemCachedClient cachedClient;
@PostConstruct
public void init()
{
cachedClient = new MemCachedClient();
// 获取连接池实例
SockIOPool pool = SockIOPool.getInstance();
// 设置缓存服务器地址,可以设置多个实现分布式缓存
pool.setServers(new String[] {server});
// 设置初始连接5
pool.setInitConn(5);
// 设置最小连接5
pool.setMinConn(5);
// 设置最大连接250
pool.setMaxConn(250);
// 设置每个连接最大空闲时间3个小时
pool.setMaxIdle(1000 * 60 * 60 * 3);
// 设置连接池维护线程的睡眠时间
// 设置为0,维护线程不启动
// 维护线程主要通过log输出socket的运行状况,监测连接数目及空闲等待时间等参数以控制连接创建和关闭。
pool.setMaintSleep(30);
// 设置是否使用Nagle算法,因为我们的通讯数据量通常都比较大(相对TCP控制数据)而且要求响应及时,因此该值需要设置为false(默认是true)
pool.setNagle(false);
// 设置socket的读取等待超时值
pool.setSocketTO(3000);
// 设置socket的连接等待超时值
pool.setSocketConnectTO(0);
// 设置完pool参数后最后调用该方法,启动pool。
pool.initialize();
}
public void add(String key, Object value)
{
cachedClient.set(key, value);
}
public boolean add(String key, Object value, int milliseconds)
{
return cachedClient.add(key, value, milliseconds);
}
public boolean add(String key, Object value, Date milliseconds)
{
return cachedClient.add(key, value, milliseconds);
}
public void remove(String key)
{
cachedClient.delete(key);
}
public Object get(String key)
{
return cachedClient.get(key);
}
}
锁相关操作核心代码
String value = RandomStringUtils.randomNumeric(8);
if (memcachedLock.add("key", value, new Date(System.currentTimeMillis() + 30 * 1000)) == false)
{
log.info("报名或抢购失败,请稍后再试! 锁持有者:{}", memcachedLock.get("key"));
return;
}
StopWatch clock = new StopWatch();
try
{
// 领取成功
log.info("★★★★★★★★ {} 报名或抢购处理中★★★★★★★★", memcachedLock.get("key"));
clock.start();
// 模拟耗时业务操作
TimeUnit.MILLISECONDS.sleep(RandomUtils.nextInt(10000, 20000));
clock.stop();
log.info("{} 运行 {} ms ---------------", memcachedLock.get("key"), clock.getLastTaskTimeMillis());
}
finally
{
memcachedLock.remove("key");
log.info("释放memcachedLock锁");
}
本地运行效果
docker运行效果
docker运行方式同 分布式锁实现一
有任何问题和建议,都可以向我提问讨论,大家一起进步,谢谢!
-over-