AQS的原理(1)

来源:互联网 发布:java二维数组 编辑:程序博客网 时间:2024/06/18 18:33

AQS


AQS中同步状态

其中state表示同步状态,为32位整数,用来表示锁的数量。

AQS主体流程

AQS中提供了获取和释放锁有两种模式:独占式和共享式。

1.  独占模式:

1)  acquire:以独占的模式获取对象,忽略中断。

2)  acquireInterruptibly:以独占模式获取对象,如果中断则停止。

3)  release:以独占模式释放对象。

2.  共享模式:

1)  acquireShared:以共享模式获取对象,忽略中断。

2)  acquireSharedInterruptibly:以共享模式获取对象,如果被中断则中止。

3)  releaseShared:以共享模式释放对象。

PS:独占模式可以视为共享模式的特例,共享数量为1.

3.  主体流程:

1)  线程通过acquireSharedInterruptibly获取锁,操作完成后。

2)  通过releaseShared来释放锁。


3)  程序获取锁失败后(通过调用acquireSharedInterruptibly),将进入等待队列,然后进入阻塞状态(经过一些判断之后)

4)  当另一个线程释放锁后(通过调用releaseShared),将执行唤醒阻塞线程的操作;被唤醒的线程将把自己移出等待队列,并执行一些其它操作

等待队列

AQS中使用FIFO的队列来管理等待获取锁的线程。

1.        主要流程:

1)        入队列:线程获取锁失败后,调用doAcquireSharedInterruptibly方法。

a)        创建一个新的结点。

b)        将结点添加到等待队列队尾。

c)        将线程阻塞。

2)        唤醒:其它线程释放锁资源,调用releaseShared中doReleaseShared方法。

a)        获取队列中的第一个结点。

b)        将节点对应线程唤醒。

c)        该线程将尝试获取锁,成功后将自己移除等待队列。

d)        判断是否仍然有空闲锁,若有则继续唤醒下一个结点。

2.        每次只会唤醒第一个节点,如果同时释放多个锁,后续的节点将由前面被唤醒的节点来唤醒,尽量减少数据竞争。

阻塞机制

1.        作用:

1)        阻塞新添加到等待队列中的线程。

2)        唤醒等待队列中对头的等待线程。

2.        实现:使用Unsafe的park和unpark实现的


Condition

1.        作用:Condition实例始终被绑定到一个锁(Lock)上,Lock替代了Java的synchronized方法,而Condition则替代了Object的监视器方法,包括wait、notify和notifyAll。即起到线程间通信的作用。提供awaitsignalsignalAll方法。

2.        使用:


3.        主要方法:

1)        Await():阻塞当前前程,直到有信号到来唤醒它。

a)        可能被唤醒的时机:

Ø  其他某线程调用了此Condition的signal()方法

Ø  其他某线程调用此Condition的SignalAll()方法

Ø  其他某线程中断当前线程

Ø  超过指定等待时间

Ø  发生“虚假唤醒”

否则一直处于等待状态

b)        阻塞过程:

1.      如果当前线程被中断,则抛出中断异常;

2.      入队:将当前线程放置到Condition的等待队列中;

3.      释放锁资源:释放当前线程的锁,并且保存锁定状态;

4.        循环检测:在收到信号、中断或超时前,一直阻塞;

5.        放行:使用保存的锁定状态重新获取锁;

6.        如果步骤4的阻塞过程中发生中断,则抛出中断异常

PS:将阻塞放入到循环中---à防止“虚假唤醒”

         保存锁定状态---------à使用排他模式

2)        Signal():唤醒一个线程。即将当前Condition的等待队列中的第一个结点移动到拥有锁的等待队列中等待执行。

3)        signalAll():将当前Condition的等待队列中的所有结点移到拥有锁的等待队列中。等待执行。

0 0