美文网首页
Java基础-线程 (五)

Java基础-线程 (五)

作者: 森屿暖茶 | 来源:发表于2021-02-01 14:51 被阅读0次

    队列同步器AQS:AbstractQueuedSynchronizer )

    AQS是用来构建锁或者其他同步组件的基础框架,它使用了一个int成员变量表示同步状态,通过内置的FIFO队列来完成资源获取线程的排队工作。

    AbstractQueuedSynchronizer是一个抽象方法。AQS的使用方式是继承。子类通过实现AbstractQueuedSynchronizer的抽象方法来管理同步状态。AbstractQueuedSynchronizer中有一个volatile int state来记录代表这个同步状态。主要通过以下3个方法获取或者改变同步状态:

    ①getState():获取当前同步状态。

    ②setState(int newState):设置当前同步状态。

    ③compareAndSetState(int expect,int update):使用CAS设置当前状态,该方法能够保证状态设置的原子性。 

    AQS使用的设计模式,模板方法设计模式。

    模板方法设计模式

    AQS的基本思想CLH队列锁,每一个需要拿锁的线程打包成一个节点,挂到链表上,每个线程不断自旋检测前一个节点是否释放锁,释放锁当前线程就可以拿到这把锁。

    CLH队列锁是一种基于链表(双向链表)的可扩展、高性能、公平的自旋锁,申请线程仅仅在本地变量上自旋,它不断轮询前驱的状态,假设发现前驱释放了锁就结束自旋。

    结构:QNode,包含myPred(前驱结点)和Locked(当前是否需要获得锁,true为锁需求)。仅当myPred前驱结点值为false时。该QNode节点才能拿到锁。所以链表内的每个节点都在不断的自旋检查myPred的前驱结点Locked是否为false。

    假设有A和B 2个线程。A和B分别创建2个QNode。A和B都需要拿到锁。

    (1)当A拿到锁,A的myPred=true,locked=true.B的myPred=QNodeA,locked=true.

    (2)B开始自旋它的前节点 locked是否为false,为false时代表A释放锁。

    (3)A释放锁B拿到锁时,A的myPred=true,locked=false,B的myPred=true,locked=true.

    (4)若还有C、D、E类似节点重复(1)(2)(3)。

    AQS实际节点。AQS优化了CLH思想,拿不到锁的节点会自旋一定次数后就挂起节点。实际synchronized也是实现CLH队列锁的思想来实现的。区别在于AQS的的等待队列有多个,synchronized等待队列只有1个。

    使用:

    独占式实现以下2个方法。自行实现内容。

    独占式

    共享式实现以下3个方法。自行实现内容。

    共享式

    实现类似ReentrantLock功能(供参考,具体需求具体自行实现):

    公平锁:必须按部就班的排队等待拿锁。(也称独占锁)

    非公平锁:可插队拿锁,时间片轮转机制轮到谁就给谁。

    相关文章

      网友评论

          本文标题:Java基础-线程 (五)

          本文链接:https://www.haomeiwen.com/subject/emcrnktx.html