【Concurrency】之 超越内置锁(使用ReentrantLock)

前言

内置锁虽然方便但限制很多:

  1. 一个线程因为等待内置锁而进入阻塞之后,就无法中断该线程了
  2. 尝试获取内置锁时,无法设置超时
  3. 获得内置锁,必须使用synchronized块

    
    sychronized(object) {
       //  使用共享资源 ...
    }
    


一、使用ReetrantLock


ReetrantLock 提供显式的 lockunlock 方法

// ReetrantLock 代替 synchronized
Lock lock = new ReetrantLock();
lock.lock();
try {
    // 使用共享资源
} finally {
    lock.unlock();
}


(1)可中断的锁

这里写图片描述


(2)超时

ReentrantLock 可以为获取锁的操作设置超时时间
lock.tryLock(1000, TimeUnit.MILLISECONDES);


(3)交替锁(head-over-hand locking)

在链表中插入一个节点。
1. 用锁保护整个链表(但链表加锁时其他使用者无法访问链表)
2. 交替锁可以只锁住链表的一部分(允许不涉及被锁部分的其他线程自由访问链表)


(4)条件变量
并发编程经常需要等待某个事件发生。
  1. 从队列删除元素前需要等待队列非空
  2. 向缓存添加数据前需要等待缓存有足够的空间
// 建议按照下面的模式使用条件变量:
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();

lock.lock();
try {
    while (! <<条件为真>>) {
        condition.await();
    }
    // 使用共享资源
} finally {
    lock.unlock();
}

当另一个线程调用了signal() 或者 signalAlll(),意味着对应的条件可能变为真,await()将原子地回复运行并重新加锁。




二、原子变量


关于之前自增,java.util.concurrent.atomic包提供了更好的方案:
这里写图片描述
AtomicInteger 的 incrementAndGet()方法功能上等价于++count(AtomicInteger 也提供了getAndIncrement方法,等价于count++)。不过与++count 不同,incrementAndGet()方法是原子操作。

原子变量是无锁(lock-free)非阻塞(non-blocking)算法的基础,这种算法可以不用锁和阻塞来达到同步的目的。




三、再想想


  1. ReentrantLock创建时可以设置一个描述公平性的变量。什么是“公平”的锁?何时适合使用公平的锁?使用非公平的锁会怎样?
  2. 什么是ReentrantReadWriteLock?它与ReentrantLock有什么区别?使用与什么场景?
  3. 什么是“虚假唤醒”(spurious wakeup)什么时候发生虚假唤醒?为什么符合规范的代码不用担心虚假唤醒?
  4. 什么是AtomicIntegerFieldUpdater?它与AtomicInteger有什么区别?适合用于什么场景?




四、小结


ReentrantLock和java.util.concurrent.atomic可以做:
  1. 在线程获取锁时中断它
  2. 设置线程获取锁的超时时间
  3. 按任意顺序获取和释放锁
  4. 用条件变量等待某个条件变成真
  5. 使用原子变量避免锁的使用
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值