学习第三天(为什么分布式环境下synchronized失效?如何解决这种情况?)

举报
minjie 发表于 2021/01/21 14:36:13 2021/01/21
【摘要】 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、提供的第三方库有curatorCurator提供的InterProcessMutex是分布式锁的实现。acquire方法获取锁,release方法获取锁。
基于缓存(redis)来实现分布式锁

采用jedis.setnx()jedis.expire()组合实现加锁。setnx()方法作用就是SET IF NOT EXISTexpire方法就是给锁加一个过期时间。由于这是两条Redis命令,不具有原子性,如果程序在执行完setnx()之后突然崩溃,导致锁没有设置过期时间。那么就会发生死锁。

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。