ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

condition源码分析

2022-04-11 16:00:06  阅读:132  来源: 互联网

标签:分析 node lock Node 源码 new 节点 condition


目录:

1:注意事项

condition是ReentrantLock中的对象,使用condition必须配合lock锁一起使用,否则会报错,原因以下会分析

2:创建方式

ReentrantLock lock = new ReentrantLock(); 

Condition fullCondition =lock.newCondition();

3:使用案例

package com.saytoyou.com.thread;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class ConditionTest {

    public static void main(String[] args) {

        ReentrantLock lock = new ReentrantLock();

        Condition condition = lock.newCondition();
        
        new Thread(new Runnable() {
            @Override
            public void run() {
                lock.lock();
                System.out.println("你好,我抢到了资源开始执行");
                try {
                    condition.await();
                    System.out.println("我又获取到资源了");
                }catch (Exception e){
                    e.printStackTrace();
                }finally {
                    lock.unlock();
                }

            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                lock.lock();
                System.out.println("你好,我是线程signal");
                try {
                    condition.signal();
                    System.out.println("开始释放资源");
                }catch (Exception e){
                    e.printStackTrace();
                }finally {
                    lock.unlock();
                }

            }
        }).start();
        
    }
}

说明:需要注意的是,signal必须是在await方法之前执行,不然会导致死锁,好了接下来进行源码分析

4:源码分析await方法

await源码如下

 public final void await() throws InterruptedException {  
            if (Thread.interrupted())
                throw new InterruptedException();
            Node node = addConditionWaiter();  加入等待队列
            int savedState = fullyRelease(node);  释放当前线程占用的锁资源,因为线程不知道state是几,所以释放完成,返回state的值,保存起来
            int interruptMode = 0;
            while (!isOnSyncQueue(node)) {  循环判断是否在同步队列中,在同步队列中,说明signal调用了,可以进行如下操作,否否则等待
                LockSupport.park(this);
                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                    break;
            }
            if (acquireQueued(node, savedState) && interruptMode != THROW_IE) 利用AQS放入阻塞队列,尝试获取资源,等待唤醒
                interruptMode = REINTERRUPT;
            if (node.nextWaiter != null) // clean up if cancelled    
                unlinkCancelledWaiters();
            if (interruptMode != 0)
                reportInterruptAfterWait(interruptMode);
        }

whille()循环详解,刚开始进来肯定不在同步对列中,所以false进入循环,park,等待唤醒,唤醒之后不管下面if循环是否有效,再次进入while循环,这时候


肯定已经在同步队列了,所以会跳出循环,进行接下来的操作

 

上述addConditionWaiter源码如下

 private Node addConditionWaiter() {
            Node t = lastWaiter;
            // If lastWaiter is cancelled, clean out.
            if (t != null && t.waitStatus != Node.CONDITION) {
                unlinkCancelledWaiters();  清除队列中不是condition状态的节点
                t = lastWaiter;
            }
            Node node = new Node(Thread.currentThread(), Node.CONDITION);
            if (t == null)
                firstWaiter = node;
            else
                t.nextWaiter = node;
            lastWaiter = node;
            return node;
        }
新建一个node节点,赋值为-2也就是condition状态,然后加入到队列尾部,同时把最后一个lastWaiter指向新节点

unlinkCancelledWaiters,方法就是把队列中不是condition状态的节点清楚掉

unlinkCancelledWaiters方法如下

 private void unlinkCancelledWaiters() {
            Node t = firstWaiter;
            Node trail = null;
            while (t != null) {
                Node next = t.nextWaiter;
                if (t.waitStatus != Node.CONDITION) {
                    t.nextWaiter = null;  帮助gc
                    if (trail == null)
                        firstWaiter = next;
                    else
                        trail.nextWaiter = next;  如果发现状态不正确,就把上个节点剔除,保存当前节点
                    if (next == null)
                        lastWaiter = trail;
                }
                else
                    trail = t;  存放上一个节点
                t = next; 存放当前节点,循环往上
            }
        }
大概就是trail保存上一个节点,t保存当前节点,循环往下,如果t节点的下个节点状态不正确,就把t剔除,直接用下一个节点关联到上一个节点

回到addwaiter方法中

int savedState = fullyRelease(node);该方法的主要作用就是释放调用await方法的线程的锁资源,同时临时返回state的值,供后面使用
final int fullyRelease(Node node) {
        boolean failed = true;
        try {
            int savedState = getState(); 
            if (release(savedState)) {
                failed = false;
                return savedState;
            } else {
                throw new IllegalMonitorStateException();
            }
        } finally {
            if (failed)
                node.waitStatus = Node.CANCELLED;
        }
    }

 





标签:分析,node,lock,Node,源码,new,节点,condition
来源: https://www.cnblogs.com/xzlnuli/p/16130351.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有