9月 132019
 

课程链接

课程:https://url.163.com/VD8

java锁

synchronized

在jdk 1.5以后,优化了,使其性能并不是像很多帖子说的那样,“非常重”

JUC lock

方法 说明
lock() 获取锁,如果锁被暂用则一直等待
tryLock() 如果获取锁的时候锁被占用就返回false,否则返回true
tryLock(long time, TimeUnit unit) 比起tryLock,多出等待时间
unLock()
lockInterruptibly()

lock与synchronized区别

  • lock是接口,syn是java关键字,是内置实现;
  • sync 发生异常时自动释放线程占有的锁,因此不会导致死锁现象发生;lock在发生异常时,如果没有unLock去释放锁,可能造成死锁。因此使用lock时需要在finally中释放锁
  • lock 可以让等待锁的线程响应中断;sync 不行,使用sync等待线程一直等待下去,不能中断
    lock可以知道有没有成功获得锁,sync则无法知道
  • lock可提高多线程读效率

性能上,竞争不激烈,两者性能;竞争激烈时,lock性能远由于sync。具体需要根据情况而定。
并不一定总是需要用lock,sync更方便,lock需要更精心维护代码、避免死锁

分布式锁

push
pull
的方式

惊群效应

分布式锁需要具备的条件:

  • 互斥性
  • 可重入
  • 超时高效
  • 阻塞/非阻塞

几种实现方式:

  1. 数据库实现(乐观锁)
  2. 基于zookeeper的实现
  3. 基于redis的实现
  4. 自研分布式锁(google的chubby, zookeeper实际上是基于这个chubby)

基于数据库实现

基于redis的实现

基本命令

SETNX key value   

if key不存在,则设置为value;存在则不做任何操作
“SET if Not eXist”

expire key seconds 

设置过期时间,如果key已国企,则将会被自动删除。

del key

删除key

实现方式

基本锁

原理:利用redis的setnx,如果不存在某个key则设置值,设置成功则表示锁成功
缺点:如果获取锁后的进程在没有执行完就挂了,则锁永远不会释放

改进型

改进:在基本形式锁上setnx后设置expire,保证超时后也能自动释放锁
缺点:setnx与expire不是一个原子操作,可能执行完setnx该进程就挂了

再改进

lua执行具有原子性
改进:利用lua脚本,将setnx与expire编程一个原子操作,可解决一部分问题
缺点:还是会出现锁过期的问题

具体实现

官方提供的java组件:redisson
redisson的分布式可重入锁RLock java对象实现了java.util.concurrent.locks.lock接口同时还支持过期解锁
地址:

分布式锁方案比较

  • 从理解的难易程度(从低到高)
    数据库 > 缓存 > zookeeper
  • 从实现的复杂性角度
    zookeeper >= 缓存 > 数据
  • 从性能角度(从高到底)
    缓存 > zookeeper >= 数据库
  • 从可靠性角度(从高到低)
    zookeeper > 缓存 > 数据库

扩展

redis的可以用于哪些场景?

  • 缓存
  • 消息队列
  • 分布式锁
  • 发布订阅

 


 Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

(required)

(required)