lockSupport.park()和普通的wait|notify都有啥区别?
- 面向的主体不一样 。LockSuport主要是针对Thread进进行阻塞处理 , 可以指定阻塞队列的目标对象 , 每次可以指定具体的线程唤醒 。Object.wait()是以对象为纬度 , 阻塞当前的线程和唤醒单个(随机)或者所有线程 。
- 实现机制不同 。虽然LockSuport可以指定monitor的object对象 , 但和object.wait() , 两者的阻塞队列并不交叉 。可以看下测试例子 。object.notifyAll()不能唤醒LockSupport的阻塞Thread.
6.总体流程图
文章插图
代码中频繁出现的interruptd中断标记是做什么用的?对线程调用 t1.interrupt();时
会导致 LockSupport.park() 阻塞的线程重新被唤醒
即有两种唤醒情况: 被前置节点唤醒 , 或者被外部中断唤醒
这时候要根据调用的acuire类型决定是否在中断发生时结束锁的获取 。
上面介绍的是不可中断锁 。
在parkAndCheckInterrupt中 , 当park结束阻塞时时,使用的是 Thread.interrupted() 而不是 .isInterrupted() 来返回中断状态
因为前者会返回线程当前的中断标记状态同时清除中断标志位(置为false)
外层CAS循环时 , 就不会让线程受中断标记影响 , 只是记录一下是否发生过中断
文章插图
当获取锁成功后 , 如果发现有过线程中断 , 则会触发中断异常 ,
文章插图
之后便由获取锁的调用者自己决定是否要处理线程中断 。像下面这样:
reentrantLock.lock();try { System.out.println("t1"); TimeUnit.SECONDS.sleep(30);} catch (InterruptedException e) { e.printStackTrace();} finally { reentrantLock.unlock();}那么另一种情况就是可中断锁了 。
ReentranLock有一个lockInterruptibly()方法就是这种情况
线程被唤醒时 , 如果发现自己被中断过 , 就会直接抛异常而不是继续获取锁
文章插图
因此如果你的线程对中断很敏感 , 那么就是用可中断锁 , 及时响应 。
如果不敏感 , 也要注意处理中断异常 。
AQS的详细资源释放流程首先AQS提供的模板方法为release方法 。
核心逻辑就是对资源进行尝试性释放
如果成功 , 就唤醒等待队列中的第一个头节点
public final boolean release(int arg) { // 是否释放成功 , tryRelease是子类要实现的方法 if (tryRelease(arg)) { Node h = head; // 判断头节点是否正在阻塞中 , 是的话唤醒 if (h != null && h.waitStatus != 0) // 唤醒头节点 unparkSuccessor(h); return true; } return false; }看一下ReteenLock中的tryRelease实现
就是减一下资源值 。
当资源值清零 , 则说明可以解除了对当前点的占用
protected final boolean tryRelease(int releases) { int c = getState() - releases; if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) {free = true; // 设置当前占用线程为null setExclusiveOwnerThread(null); } // 不需要CAS , 因为只有持有锁的人才能做释放 , 不担心竞争 setState(c); return free; }
经验总结扩展阅读
- 许运东婉萍是什么电视剧中的人物?
- 为什么女儿9岁了睡觉头上出汗
- 迎战高考的励志祝福文案
- 许舒贝是什么电视剧中的人物?
- 裘正宇是什么电视剧中的人物?
- 西厂雨化田是什么电影中的人物?
- Briefings in Bioinformatics-2021 知识图谱-生物信息学-医学顶刊论文:生物信息学中的图表示学习:趋势、方法和应用
- 苏简和黄凯迪是什么电视剧中的人物?
- 3步训练培养你心目中的小神童
- 艾莉是什么电视剧中的人物?