Java并发编程——AQS组件之ReentrantLock、ReentrantReadWriteLock、StempedLock以及Condition

如何选择锁

  1. 当只有少量竞争者,使用synchronized
  2. 竞争者不少但是线程增长的趋势是能预估的,使用ReetrantLock
  3. synchronized不会造成死锁,jvm会自动释放死锁。

一、可重入锁ReentrantLock

1.ReentrantLock介绍

java中有两类锁,一类是Synchronized,而另一类就是J.U.C中提供的锁。ReentrantLockSynchronized都是可重入锁,本质上都是lockunlock的操作。

2.ReentrantLockSynchronized的对比

  • 可重入性:两者的锁都是可重入的,差别不大,有线程进入锁,计数器自增1,等下降为0时才可以释放锁;
  • 锁的实现:synchronized是基于JVM实现的(用户很难见到,无法了解其实现),而ReentrantLock是JDK实现的,可以通过查看源码来分析具体实现。
  • 性能区别:在最初的时候,二者的性能差别差很多,当synchronized引入了偏向锁、轻量级锁(自选锁)后,二者的性能差别不大,官方推荐synchronized(写法更容易、在优化时其实是借用了ReentrantLockCAS技术,试图在用户态就把问题解决,避免进入内核态造成线程阻塞);
  • 功能区别
     1. 便利性synchronized更便利,它是由编译器保证加锁与释放。ReentrantLock是需要手动释放锁,所以为了避免忘记手工释放锁造成死锁,所以最好在finally中声明释放锁。
     2. 锁的细粒度和灵活度ReentrantLock优于synchronized

3.ReentrantLock的优势

  1. ReentrantLock可以指定是公平锁还是非公平锁,synchronized只能是非公平锁。(所谓公平锁就是先等待的线程先获得锁)
  2. ReentrantLock提供了一个Condition类,可以分组唤醒需要唤醒的线程。不像是synchronized要么随机唤醒一个线程,要么全部唤醒。
  3. 提供能够中断等待锁的线程的机制,通过lock.lockInterruptibly()实现,这种机制 ReentrantLock是一种自选锁,通过循环调用CAS操作来实现加锁。性能比较好的原因是避免了进入内核态的阻塞状态。

4.synchronized的优势

 从上边的介绍,看上去ReentrantLock不仅拥有synchronized的所有功能,而且有一些功能synchronized无法实现的特性。性能方面,ReentrantLock也不比synchronized差,那么到底我们要不要放弃使用synchronized呢?答案是不要这样做

synchronized的优势

J.U.C包中的锁定类是用于高级情况和高级用户的工具,除非说你对Lock的高级特性有特别清楚的了解以及有明确的需要,或这有明确的证据表明同步已经成为可伸缩性的瓶颈的时候,否则我们还是继续使用synchronized。相比较这些高级的锁定类,synchronized还是有一些优势的,比如synchronized不可能忘记释放锁。还有当JVM使用synchronized管理锁定请求和释放时,JVM在生成线程转储时能够包括锁定信息,这些信息对调试非常有价值,它们可以标识死锁以及其他异常行为的来源。

5.ReentrantLock的使用示例

代码如下所示:

@Slf4j
@NotThreadSafe
public class LockExample2 {
   

    // 请求总数
    public static int clientTotal = 5000;

    // 同时并发执行的线程数
    public static int threadTotal = 200;

    public static int count = 0;

    //声明锁的实例
    private final static Lock lock = new ReentrantLock();

    public static void main(String[] args) throws Exception {
   
        ExecutorService executorService = Executors.newCachedThreadPool();
        final Semaphore semaphore = new Semaphore(threadTotal);
        final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
        for (int i = 0; i < clientTotal ; i++) {
   
            executorService.execute(() -> {
   
                try {
   
                    semaphore.acquire();
                    add();
                    semaphore.release();
                } catch (Exception e) {
   
                    log.error("exception", e);
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值