目录:
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 举报,一经查实,本站将立刻删除。