随着当前应用的日益庞大和复杂场景,单服务应用已经越来越无法支持日常需求,因此集群环境、分布式环境应用而生。java提供的jvm锁只能对单jvm方法进行加锁,以保持线程安全,对于跨jvm(多jvm)将无法发挥其作用,因此有了分布式锁。
常见的分布式锁
常见的分布式锁有以下几种方式
mysql:通过表的行锁来实现分布式锁
redis:通过redis提供的set nx px命令,来实现分布式锁
zookeeper:通过zookeeper提供的临时有序节点,来实现分布式锁
除了常见的三种分布式锁,还有其他方式吗
在考虑用其他方式实现的基础下,我们先了解下锁的原理:
锁的目的是当有线程使用特定资源的时候,保证其他线程不能操作被锁的资源,即排他性,因此分布式锁的核心原理就是在不同主机(JVM),通过一个共享资源来标记锁的获得与否,保证其他线程访问被锁的资源时互斥。
之前干货君使用mongodb实现过一个分布式锁:精通分布式锁?那用mongodb实现一个吧
下面我们在了解原理的情况下,我们基本可以用很多第三方应用来实现,下面我们用memcache来实现一个分布式锁
memcache分布式锁
注意:Memcache是这个项目的名称,而memcached是它服务器端的主程序文件名,很多人傻傻分不清。
安装memcached服务就不描述了,大家可以自行查询,下面主要介绍下memcache:
Memcached是一个自由开源的,高性能,分布式内存对象缓存系统。它与redis的区别主要体现在如下几个方面:
- redis支持的数据结构类型较多,memcached主要存储字符串和对象
- redis集群通过hash槽实现,memcached通过一致性hash
- memcached不支持持久化,redis可以持久化
那么我们实现分布式锁主要使用memcached以下几个命令:
add 命令:用于将 value(数据值) 存储在指定的 key(键) 中。如果 add 的 key 已经存在,则不会更新数据,之前的值将仍然保持相同,并且您将获得响应 NOT_STORED。get 命令:获取存储在 key(键) 中的 value(数据值) ,如果 key 不存在,则返回空。delete 命令:用于删除已存在的 key(键)。
下面我们用Java代码实现一下
引入依赖
spy memcached 2.4rc1
Java实现
public class MemcacheLock implements DistributedLock{ public static MemcachedClient memcachedClient; static { try { memcachedClient = new MemcachedClient(new InetSocketAddress(11211)); } catch (IOException e) { e.printStackTrace(); } } @Override public boolean lock(String key, String requestId) { // 如果key存在则失败,否则添加成功 Future add = memcachedClient.add(key, 100,requestId); try { Boolean result = add.get(); return result; } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } return false; } @Override public boolean unlock(String key, String requestId) { // 获取key的值 Object o = memcachedClient.get(key); // 判断requestId是不是相等 if (requestId.equals(o)){ // 删除key Future delete = memcachedClient.delete(key); try { return delete.get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } return false; }}
其实memcached还可以使用cas命令来实现分布式锁,有兴趣的可以研究一下