标签:阿里 线程等待 sem 共享资源 air 执行 exception ica vol
AQS(
AbstractQueuedSynchronizer),抽象的队列式同步器
AQS 维护了一个 state(共享资源变量)和一个 FIFO 线程等待队列(CLH 队列),多个线程竞争 state 被阻塞时就会进入此队列中。
state 使用 volatile 修饰的一个 int 类型的共享资源变量
资源共享的两种方式:
简短说就是一个双向链表,使用内部类 Node 来实现的。head、tail 指针分别指向链表的头部和尾部。
我们一般常用的写法如下:
ReentrantLock lock = new ReentrantLock();
// 加锁
lock.lock();
// 业务逻辑代码
...
// 解锁
lock.unLock();
那在加锁和解锁的具体过程究竟是怎么样的呢,肥壕举了两个比较简单的例子
线程 A、B、C 同时抢占锁,此时线程 B 抢占成功,线程 A、C 则失败,具体流程如下:
此时线程 B 执行完业务逻辑后,调用 lock.unlock(),具体流程如下:
这也是平时面试经常被问到的一个问题,这里简要谈一谈
具体相关代码可以看 ReentrantLock 下的两个静态类 FairSync、NonFairSync
ReentrantLock 中可以通过 newCondition() 方法创建一个 Condition 对象,那这个对象究竟是啥玩意呢?
简单说,替代传统的 Object 的 wait()、notify() 实现线程间的协作。
先来看一个使用实例:
public class Demo {
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void methodAwait() {
try {
lock.lock();
System.out.println(String.format("### 当前线程:%s waiting ###", Thread.currentThread().getName()));
condition.await();
System.out.println(String.format("### 当前线程:%s finished ###", Thread.currentThread().getName()));
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void methodSignal() {
try {
lock.lock();
System.out.println(String.format("### 当前线程:%s signal ###", Thread.currentThread().getName()));
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public static void main(String[] args) throws InterruptedException {
Demo demo = new Demo();
Thread t1 = new Thread(() -> demo.methodAwait(),"thread-A");
Thread t2 = new Thread(() -> demo.methodAwait(), "thread-B");
Thread t3 = new Thread(() -> demo.methodAwait(), "thread-C");
Thread t4 = new Thread(() -> demo.methodSignal(), "thread-D");
t1.start();
t2.start();
t3.start();
Thread.sleep(2000);
t4.start();
}
}
线程 A、B、C、D 同时启动抢占锁,这时抢占成功的线程会执行自己的逻辑业务,抢占失败的就会像上面所说,进入线程CLH 队列中。
假设线程 B 先获取锁,调用 condition.await() 方法后释放锁,阻塞并进入条件等待队列,线程 A 、C 获取锁后也依次进入条件等待队列。
线程 D 获取锁后调用 condition.signalAll() 方法,它会将条件等待队列中的线程放入 CLH 队列,并唤醒所有的等待线程。
注意,条件队列中的线程是依次一个一个加入 CLH 队列的队尾。
LockSupport
在 AQS 中,队列中线程的阻塞唤醒都是通过 LockSupport 实现的。
LockSupport 类,是用来创建锁和其他同步类的基本线程阻塞原理,核心方法只要看这两个:
park() :阻塞当前调用线程
unpark():唤醒指定线程
相比Object 类中的 wait()、notify()、notifyAll(),区别是:
【免责声明:本文图片及文字信息均由千锋重庆Java培训小编转载自网络,旨在分享提供阅读,版权归原作者所有,如有侵权请联系我们进行删除。】
标签:阿里 线程等待 sem 共享资源 air 执行 exception ica vol
原文地址:https://www.cnblogs.com/cqqfboy/p/14547307.html