学习第三天(为什么分布式环境下synchronized失效?如何解决这种情况?)
【摘要】 synchronized关键字失效原因在Java多线程编程中,经常会用到synchronized和lock和原子变量等,而在分布式系统中,由于分布式系统中的分布性,即多线程和多进程并发 分布在不同机器中,synchronized和lock这两种锁将失去原有锁的效果,因此需要自己实现分布式锁来处理并发问题,分布式处理并发的办法有以下三种:队列定义:将所有要执行的任务放入队列中,然后一个一个消费...
synchronized关键字失效原因
在Java多线程编程中,经常会用到synchronized和lock和原子变量等,而在分布式系统中,由于分布式系统中的分布性,即多线程和多进程并发 分布在不同机器中,synchronized和lock这两种锁将失去原有锁的效果,因此需要自己实现分布式锁来处理并发问题,分布式处理并发的办法有以下三种:
队列
定义:将所有要执行的任务放入队列中,然后一个一个消费,从而避免并发问题
乐观锁
将数据记录加版本号,如果版本号不一致就不更新,这种方式同Java的CAS理念类似。
分布式锁
常见的分布式锁有以下三种实现:
基于数据库实现的分布式锁
利用数据库表:首先创建一张锁的表主要包含下列字段:方法名、时间戳等。——方法名称要有唯一性约束
- 1、如果有多个请求同时提交到数据库时,数据库保证只有一个操作可以成功,那么操作成功的那个线程获得了该方法的锁,可以继续执行下面的方法体内容。
优化: 记录当前获得该锁的机器的主机信息和线程信息,那么下次再次获取锁的时候就可以先查询数据库,如果当前机器的主机信息和线程信息可以在数据库中查到,那么就可以直接把锁分配给它,从而实现可重入锁。 - 2、基于数据库排他锁
在查询语句后面增加for update
,数据库会在查询过程中给数据库表增加排他锁,当某条记录被加上排他锁之后,其他线程无法在该行记录增加排他锁。其他没有获取到的锁就会阻塞在select
语句上,从而有两种可能的结果:在超时之前获取到了锁和在超时之前没有获取到锁。获得排他锁的线程即可获取分布式锁,当获取到锁之后,可以执行方法的业务逻辑,执行完方法之后,释放锁connection.commit()
。存在的问题主要是性能不高和sql
超时的异常。
基于Zookeeper实现分布式锁
基于
Zookeeper
临时有序节点可以实现的分布式锁。每个客户端对某个方法加锁时,在Zookeeper
上与该方法对应的指定节点的目录下,生成一个唯一的瞬时有序节点。
- 1、判断是否获取锁的方式只需要判断有序节点中的序号最小的一个。当释放锁的时候,只需将这个瞬时节点删除即可。同时,其可以避免服务宕机导致的锁无法释放,而产生的死锁问题。
- 2、提供的第三方库有
curator
,Curator
提供的InterProcessMutex
是分布式锁的实现。acquire
方法获取锁,release
方法获取锁。
基于缓存(redis)来实现分布式锁
采用jedis.setnx()
和jedis.expire()
组合实现加锁。setnx()
方法作用就是SET IF NOT EXIST
,expire
方法就是给锁加一个过期时间。由于这是两条Redis
命令,不具有原子性,如果程序在执行完setnx()
之后突然崩溃,导致锁没有设置过期时间。那么就会发生死锁。
【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)