J.U.C — Locks — ReentrantLock(二)

2024-03-14 17:48
文章标签 locks reentrantlock

本文主要是介绍J.U.C — Locks — ReentrantLock(二),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

条件变量Condition

Condition实现了synchronized同步器的wait/notify/notifyAll的功能,Condition接口提供的API如下:


Condition需要与Lock绑定,一个Lock可以有多个Condition,获取Condition的方式是lock.newCondition()。Condition的实现类在AQS中的ConditionObject,类部维持了一个等待队列:


  • 获取Condition
lock.newCondition() -->// ReentrantLock
public Condition newCondition() {return sync.newCondition();
}// ReentrantLock.Sync
final ConditionObject newCondition() {return new ConditionObject();
}-->// AQS.ConditionObjectpublic ConditionObject() { }

  •  await()
	public final void await() throws InterruptedException {if (Thread.interrupted())     // 如果当前线程被终端,抛出异常throw new InterruptedException();Node node = addConditionWaiter();     // 1. 将当前线程添加到Condition队列int savedState = fullyRelease(node);     // 2. 释放锁int interruptMode = 0;while (!isOnSyncQueue(node)) {     // 3. 自旋直到被signal或signalAll唤醒LockSupport.park(this);     // 挂起当前线程if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)break;}if (acquireQueued(node, savedState) && interruptMode != THROW_IE)    // 4. 自旋去获取锁interruptMode = REINTERRUPT;if (node.nextWaiter != null) // clean up if cancelledunlinkCancelledWaiters();if (interruptMode != 0)reportInterruptAfterWait(interruptMode);}// 1.private Node addConditionWaiter() {Node t = lastWaiter;// If lastWaiter is cancelled, clean out.if (t != null && t.waitStatus != Node.CONDITION) {unlinkCancelledWaiters();t = lastWaiter;}Node node = new Node(Thread.currentThread(), Node.CONDITION);if (t == null)firstWaiter = node;elset.nextWaiter = node;lastWaiter = node;return node;}// 2.final int fullyRelease(Node node) {boolean failed = true;try {int savedState = getState();if (release(savedState)) {     // 调用release方法释放锁failed = false;return savedState;} else {throw new IllegalMonitorStateException();}} finally {if (failed)node.waitStatus = Node.CANCELLED;}}// 3.final boolean isOnSyncQueue(Node node) {if (node.waitStatus == Node.CONDITION || node.prev == null)return false;if (node.next != null) // If has successor, it must be on queuereturn true;return findNodeFromTail(node);}private boolean findNodeFromTail(Node node) {     // 在sync队列中从尾部到头部查找是不是在sync队列中Node t = tail;for (;;) {if (t == node)return true;if (t == null)return false;t = t.prev;}}

  • signal()
				public final void signal() {if (!isHeldExclusively())     // 1. 判断是不是当前线程持有锁,只有持有锁的线程能唤醒其他等待的线程throw new IllegalMonitorStateException();Node first = firstWaiter;if (first != null)doSignal(first);     // 2. 通知Condition队列中的等待最长时间的线程,即firstWaiter}// ReentrantLock.Sync
// 1.
protected final boolean isHeldExclusively() {return getExclusiveOwnerThread() == Thread.currentThread();
}// 2.private void doSignal(Node first) {do {if ( (firstWaiter = first.nextWaiter) == null)lastWaiter = null;first.nextWaiter = null;} while (!transferForSignal(first) &&(first = firstWaiter) != null);}final boolean transferForSignal(Node node) {if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))return false;Node p = enq(node);     // 将节点加入sync队列int ws = p.waitStatus;if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))LockSupport.unpark(node.thread);return true;}

事例

假设现在有三个线程陆续调用同一个condition的await
  • 开始状态:thread-1获取锁

    1. thread-1调用await():
    用thread-1创建节点,并设置waitStatus= -2(Condition),再将thread-1加入Condition队列,队列为空,将firstWaiter和lastWaiter设为thread-1;
    调用release释放thread-1拥有的锁,并从Sync队列中移除节点;
    自旋等待唤醒

  • thread-2调用await():

  • thread-3调用await():

  •  当收到signal信号后,会从condition队列中从头开始将节点移到sync队列,并唤醒自旋获取锁

这篇关于J.U.C — Locks — ReentrantLock(二)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/809201

相关文章

java线程 yield,sleep,join,synchronized wait notify notifyAll,ReentrantLock lock condition, 生产者消费者

yield,sleep,join yield,join,sleep,join是Thread中的方法,不需要 在synchronized 代码块中调用,和synchronized 没关系,也不会释放锁。 Thread.sleep(100);Thread.yield();Thread t;t.join(); (1)yield()不一定保证让出cpu yield()只是使当前线程重新回

synchronized wait()/notify 对比 ReentrantLock await()/signal()

结论 synchronized synchronized 配合 wait()/notify 无法实现精准唤醒线程 ReentrantLock ReentrantLock 配合 Condition await()/signal() 可以实现精准唤醒线程 (指唤醒指定的线程) ReentrantLock 如何实现精准唤醒线程 一个 lock 配合多个 Condition, 且

ReentrantLock的lockInterruptibly()理解

ReentrantLock锁有几种:lock、tryLock、tryLock(long timeout, TimeUnit unit)、lockInterruptibly。 lock 阻塞等待获取锁,优先考虑获取锁,待获取锁成功后,才响应中断。 lockInterruptibly 优先考虑响应中断,而不是响应锁的普通获取或重入获取。  tryLock() 是一个有返回值的方法,试图申请一个锁

【并发】Lock与ReentrantLock

1 Lock基本使用 Lock能实现代码同步,它比synchronized更具灵活性,什么时候锁住,什么时候释放锁等都是看得见的,使用时必须使用try{}finally{},意思是万一发生异常或者错误都可以释放锁。 try{}finally{//释放锁} 使用示例 public class SaleTicket implements Runnable {private int tic

ReentrantLock可重入锁又是怎么回事?

前言:有关Synchronized锁的知识可以参考我上篇写的内容synchronized必知必会的知识点 一:ReentrantLock的实现原理 锁的实现原理基本是为了达到一个目的:让所有的线程都能看到某种标记。Synchronized通过在对象头中设置标记实现了这一目的,是一种/原生的锁实现方式,而ReentrantLock以及所有的基于LocK接口的实现类,都是通过用一个volitl

Java并发之ReentrantLock详解

原文: http://blog.csdn.net/lipeng_bigdata/article/details/52154637      一、入题         ReentrantLock是Java并发包中互斥锁,它有公平锁和非公平锁两种实现方式,以lock()为例,其使用方式为: [java] view plain copy ReentrantLoc

除了Synchronized和ReentrantLock外,有哪些别的同步机制

除了synchronized和ReentrantLock外,有哪些别的同步机制 答案: Java提供了多种同步机制和锁用来满足不同的并发需求。除synchronized和ReentrantLock之外,还有以下几种: 1. CountDownLatch(倒计时器):允许一个或多个线程等待其他线程完成操作。它维护了一个计数器,表示需要等待的事件数量。每当一个事件完成时,计数器减一。 当计数器

“J.U.C”:ReentrantLock之三unlock方法分析

前篇博客LZ已经分析了ReentrantLock的lock()实现过程,我们了解到lock实现机制有公平锁和非公平锁,两者的主要区别在于公平锁要按照CLH队列等待获取锁,而非公平锁无视CLH队列直接获取锁。但是对于unlock()而已,它是不分为公平锁和非公平锁的。 [java]  view plain copy public void unlock() {

“J.U.C”:ReentrantLock之一简介

注:由于要介绍ReentrantLock的东西太多了,免得各位客官看累,所以分三篇博客来阐述。本篇博客介绍ReentrantLock基本内容,后两篇博客从源码级别分别阐述ReentrantLock的lock、unlock实现机制。 ReentrantLock,可重入的互斥锁,是一种递归无阻塞的同步机制。它可以等同于synchronized的使用,但是ReentrantLock提供了比sync

7、深入理解AQS之独占锁ReentrantLock

深入理解AQS之独占锁ReentrantLock 管程 - Java同步的设计思想MESA模型 AQS原理分析什么是AQSAQS核心结构AQS定义两种队列同步等待队列条件等待队列 基于AQS实现一把独占锁 ReentrantLock源码分析ReentrantLock原理lock()流程图unlock()流程图 ReentrantLock源码分析构造函数lock()加锁公平锁非公平锁acqui