java 并发编程-ReentrantLock

ReentrantLock与Synchronized

ReentrantLock是一种可重入的独占锁,相对于synchronized,ReentrantLock具备如下特点:

  1. 可中断
  2. 可以设置超时时间
  3. 可以设置为公平锁
  4. 支持多个条件变量
  5. 与synchronized一样,都支持可重入

在使用时要注意4个问题:

  1. 默认情况下ReentrantLock为非公平锁而非公平锁;
  2. 加锁次数和释放锁次数一定要保持一致,否则会导致线程阻塞或程序异常;
  3. 加锁操作一定要放在try代码之前,这样可以避免未加锁成功又释放锁的异常;
  4. 释放锁一定要放在finally中,否则会导致线程阻塞。

工作原理

当有线程调用lock方法的时候:如果线程获取到锁了,那么就会通过CAS的方式把AQS内部的state设置成为1。这个时候,当前线程就获取到锁了。只有首部的节点(head节点封装的线程)可以获取到锁。其他线程都会加入到这一个阻塞队列当中。如果是公平锁的话,当head节点释放锁之后,会优先唤醒head.next这一个节点对应的线程。如果是非公平锁,允许新来的线程和head之后唤醒的线程通过cas竞争锁。

Condition

相当于synchronized中的wait()和notify()机制,通常与Lock接口(比如ReentrantLock)一起使用。调用Condition的await()和signal()方法,都必须在lock保护之内。

public class Main {
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition condition = lock.newCondition();
    public static volatile boolean flag = false;

    private void lockCondition() throws InterruptedException {
        new Thread(new Runnable() {
            @Override
            public void run() {
                lock.lock();
                try {
                    System.out.println("t1线程抢到锁");
                    while (!flag) {
                        System.out.println("t1线程等待");
                        condition.await();
                    }
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                } finally {
                    lock.unlock();
                    System.out.println("t1线程释放锁");
                }

                System.out.println("线程t1执行完成");

            }
        }, "t1").start();

        Thread.sleep(3000);
        new Thread(new Runnable() {
            @Override
            public void run() {
                lock.lock();
                try {
                    System.out.println("t2线程抢到锁");
                    flag = true;
                    condition.signal();
                } finally {
                    lock.unlock();
                    System.out.println("t2线程释放锁");
                }
                System.out.println("t2线程执行完成");
            }
        }, "t2").start();
    }

    public static void main(String[] args) throws InterruptedException {
        new Main().lockCondition();
    }
}

AQS(AbstractQueuedSynchronizer)

  1. volatile int state : 表示资源的可用状态 0 可用 1 已被占用 >1表示线程重入(线程通过cas对state写入成功就是加锁成功)
  2. 两种队列:
    2.1 同步等待队列:主要用于维护获取锁失败时入队的线程。
    2.2 条件等待队列:调用await()的时候会释放锁,然后线程会加入到条件队列,调用signal()唤醒的时候会把条件队列中的线程节点移动到同步队列中,等待再次获得锁。
    在这里插入图片描述
  3. ReentrantLock用到tryAcquire和tryRelease方法,是独占锁
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值