【并发编程】ReetrantLock

好了,在之前的文章。我们手写过一个Lock锁了,我们从锁的运行机制和原理可以认为锁是对synchronize关键字的一个增强。

那么我们来看看在Java中的JUC包中的ReentrantLock类,它是如何处理锁的?跟我们手写的Lock锁区别在什么地方。

首先我们来看看Lock接口提供的方法。

 

其中:

  • lockInterruptibly() :如果当前线程被中断了,抛出异常。如果没有就尝试的拿锁,如果拿不动就进入循环等待。
  • tryLock():如果获取到状态是可以拿锁的,使用CAS进行尝试拿锁,拿到后当前线程为持有锁线程。如果已经是拿锁线程再次tryLock那么会进行状态+1,即重入锁。
  • newCondition():这个是返回一个condition对象。指当前锁的对象。

从方法设计上来看,跟我们手写的Lock锁本意无太大出入。但要关注的一个问题是,在ReentrantLock的实现上采用了一个叫AQS模型。

ReentrantLock

我们首先了解一个知识点,在并发设计中争夺锁的时候,线程会有哪些方式去争夺。

公平方式:使用该方式会忽略等待线程进入队列的位置,当有锁被释放时,所有等待线程都可以去争夺锁。

非公平方式:使用该方式会要求等待线程按先进队先获取的方式争夺锁。

使用RentrantLock

import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

public class UsedReentrantLockTest {
    private static final ReentrantLock lock = new ReentrantLock();

    public void doProcessor() {
        lock.lock();
        try {
            Thread thread = Thread.currentThread();
            System.out.println(thread.getName()+"已经拿到锁 执行任务中");
            // 执行任务
            Random random = new Random();
            TimeUnit.SECONDS.sleep(random.nextInt(10));
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        UsedReentrantLockTest usedReentrantLockTest = new UsedReentrantLockTest();
        new Thread(usedReentrantLockTest::doProcessor, "线程-1").start();
        new Thread(usedReentrantLockTest::doProcessor, "线程-2").start();
        new Thread(usedReentrantLockTest::doProcessor, "线程-3").start();
    }
}

加锁

我们使用非公平方式来分析一下ReentrantLock的加锁机制。先看图

 其中非公平的争夺锁的体现于,队列内的Node节点按照入队顺序循环获取锁的步骤。

解锁机制

 

AQS(AbstractQueuedSynchronizer)

AQS是整个并发锁机制的核心,大致的设计结构图如下:

 

这个是一个简易版本设计图,实际上原理的设计图会更加细致与巧妙。具体的分析文章再出一篇。

我们先初步了解一下这个AQS是怎么运行以及加锁的处理。

执行步骤:

  1. 当state!=0时, 当前线程被一个Node对象接收,如果存在头部节点下将当前线程添加到队列尾部,其中 prev指向上一个节点。没有头部节点,该线程就是头部节点。
  2. 当state==0时,当前线程进行CAS操作,尝试将state=1。如果成功当前线程被当做持有锁线程。如果失败将推出本次竞争加入到队列中循环等待,尝试下一次获取锁。
  3. 当state==0且当前线程已经持有锁,该线程的state+1。

大致情况是这样,如果需要更详细的了解可以阅读源码。

0

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值