微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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;
        }
    }

 





版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐