关于aqs:AQS场景共享锁和独占锁4

1、java中,共享锁有哪些Java 中,常见的共享锁包含读写锁(ReentrantReadWriteLock)和计数器(CountDownLatch、CyclicBarrier、Semaphore 等)等。 1)读写锁读写锁是一种非凡的锁,它容许多个线程同时读取共享资源,但只容许一个线程写入共享资源。ReentrantReadWriteLock 是 Java 中实现读写锁的一种形式,它通过保护两个锁来实现读写锁的性能,即读锁和写锁。读锁能够同时被多个线程获取,而写锁只能被一个线程获取。 2)计数器计数器是一种用于管制并发拜访的同步工具,它容许多个线程并发地访问共享资源,但须要满足肯定的条件能力继续执行。常见的计数器包含 CountDownLatch、CyclicBarrier 和 Semaphore。CountDownLatch 是一种基于计数的同步工具,它能够让一个或多个线程期待一个或多个事件的产生。CyclicBarrier 是一种栅栏同步工具,它能够让多个线程在同一个工夫点上期待。Semaphore 是一种计数信号量,它能够管制同时访问共享资源的线程数量。 2、java 中,有哪些独占锁ava 中常见的独占锁包含 synchronized、ReentrantLock 和 ReentrantReadWriteLock 的写锁等。它们的特点是同一时间只能有一个线程持有锁,其余线程无法访问被锁定的代码块或资源。 1)synchronizedsynchronized 是 Java 中最根本的同步机制之一,它是一种独占锁,只能被一个线程持有。在 synchronized 关键字润饰的代码块或办法上,同一时刻只能有一个线程取得锁,其余线程须要期待取得锁的线程开释锁能力继续执行。 2)ReentrantLockReentrantLock 是 Java 中常见的独占锁实现之一,与 synchronized 相比,ReentrantLock 具备更高的灵活性和扩展性。ReentrantLock 能够设置偏心锁和非偏心锁,默认是非偏心锁。ReentrantLock 还反对可重入锁,即一个线程能够屡次获取同一个锁,而不会导致死锁。 3)ReentrantReadWriteLockReentrantReadWriteLock 是一种读写锁,读写锁容许多个线程同时读取共享资源,但只容许一个线程写入共享资源。在 ReentrantReadWriteLock 中,写锁是独占锁,即只能被一个线程持有,而读锁是共享锁,能够被多个线程同时持有。 AQS-根本篇(1)AQS-基本原理17问(2)AQS-Condition对象的应用(3)

March 7, 2023 · 1 min · jiezi

关于aqs:AQSCondition对象的使用3

AQS 中的 Condition 对象是用于实现线程间通信和同步的对象,它能够和锁对象一起应用。Condition 对象的实现依赖于期待队列,它的次要作用是将期待某个条件的线程从期待队列中挪动到条件队列中,同时在条件满足时将它们从条件队列中移回到期待队列中。 1、办法介绍1)Condition 对象的创立:Condition 对象是通过 Lock 接口中的 newCondition() 办法创立的。具体实现能够查看 ReentrantLock 和 ReentrantReadWriteLock 类中的 newCondition() 办法。 2)await() 办法的实现:await() 办法用于将以后线程退出到条件队列中,并且开释锁。具体实现中,它首先须要获取到以后线程对应的节点(Node 对象),而后将节点从期待队列中挪动到条件队列中,最初调用 release() 办法开释锁,并且挂起以后线程。 3)signal() 办法的实现:signal() 办法用于唤醒一个期待在条件队列中的线程,并且将它从条件队列中挪动到期待队列中。具体实现中,它首先须要获取到条件队列的头节点(firstWaiter),而后遍历条件队列,找到第一个不为 null 的节点,并且将它从条件队列中挪动到期待队列中,最初调用 unpark() 办法唤醒线程。 4)signalAll() 办法的实现:signalAll() 办法用于唤醒所有期待在条件队列中的线程,并且将它们从条件队列中挪动到期待队列中。具体实现中,它和 signal() 办法相似,只是在遍历条件队列时,将所有节点都挪动到期待队列中。 须要留神的是,Condition 对象的实现依赖于期待队列和 AQS 的实现,它的底层原理比较复杂。在应用 Condition 对象的时候,须要特地留神锁的开释和获取程序,以防止死锁等问题的呈现。 2、AQS的哪些锁的实现用到了condition对象AQS 中的 ReentrantLock 和 ReentrantReadWriteLock 都应用了 Condition 对象实现期待/告诉机制。1)在 ReentrantLock 中,Condition 对象是通过 newCondition() 办法创立的,它是基于 AQS 的期待/告诉机制实现的。ReentrantLock 中的 Condition 对象和 ReentrantLock 对象是绑定的,即同一个 ReentrantLock 对象中能够创立多个 Condition 对象。线程在应用 Condition 对象期待某个条件时,须要先获取对应的锁,而后通过 Condition 对象的 await() 办法进入期待状态,并且开释锁。当条件满足时,线程能够通过 signal() 或 signalAll() 办法唤醒期待在条件队列中的线程,让它们从新进入到期待队列中期待获取锁。2)在 ReentrantReadWriteLock 中,ReadLock 和 WriteLock 都实现了 Condition 接口。它们别离应用了两个 Condition 对象,别离用于实现读线程期待写线程开释锁的机制和写线程期待读线程开释锁的机制。 ...

March 7, 2023 · 2 min · jiezi

关于aqs:AQS基本原理17问

1、AQS是如何实现锁的?AQS通过定义了一个State变量来示意同步状态,同时保护了一个期待队列,当一个线程获取锁失败时,会将该线程退出到期待队列中,并将其阻塞,当锁的状态产生扭转时,AQS会从期待队列中抉择一个线程唤醒,使其有机会获取锁。 2、AQS的外围办法是哪些?AQS的外围办法包含tryAcquire(int)、tryRelease(int)、tryAcquireShared(int)、tryReleaseShared(int)、isHeldExclusively()等。 3、如何应用AQS实现独占锁?能够通过继承AbstractQueuedSynchronizer类并实现tryAcquire(int)和tryRelease(int)办法来实现独占锁。 4、如何应用AQS实现共享锁?能够通过继承AbstractQueuedSynchronizer类并实现tryAcquireShared(int)和tryReleaseShared(int)办法来实现共享锁。 5、AQS是如何实现同步的?AQS应用了一种基于FIFO期待队列的机制,当一个线程获取锁失败时,会将该线程退出到期待队列中,并将其阻塞,当锁的状态产生扭转时,AQS会从期待队列中抉择一个线程唤醒,使其有机会获取锁。 6、AQS中的State变量有什么作用?AQS中的State变量用于示意同步状态,能够用一个整型数值示意同步状态的不同状况,比方独占锁和共享锁的状态。 7、AQS中的Node节点有什么作用?AQS中的Node节点用于示意期待队列中的一个节点,其中蕴含了前驱节点、后继节点、期待状态等信息,AQS会依据这些信息进行线程的唤醒和期待。 8、AQS的期待队列是如何实现的?AQS的期待队列是通过一个双向链表来实现的,每个节点都蕴含了前驱节点和后继节点的信息,当一个线程退出期待队列时,会将一个节点退出到队列尾部,当一个线程被唤醒时,会从队列头部抉择一个节点进行唤醒。 9、AQS的tryAcquire办法和tryRelease办法的实现原理是什么?tryAcquire办法和tryRelease办法都是基于CAS(Compare and Swap,比拟并替换)操作实现的,通过原子操作批改State变量的值,以实现对锁的获取和开释。 10、AQS中的Condition对象是如何实现的?AQS中的Condition对象是基于期待队列的机制实现的,每个Condition对象都有一个期待队列,当一个线程调用Condition的await办法时,会将该线程退出到Condition的期待队列中,并开释锁,当另一个线程调用Condition的signal办法时,会从期待队列中抉择一个节点唤醒,并将其退出到主期待队列中,使其有机会获取锁。 11、AQS如何实现可重入锁?AQS实现可重入锁的形式是通过记录持有锁的线程和持有次数,在每次获取锁时判断以后线程是否曾经持有锁,如果是,则间接减少持有次数,如果不是,则通过失常的获取锁流程来获取锁。 12、AQS如何实现偏心锁?AQS实现偏心锁的形式是通过保护一个期待队列,所有期待锁的线程都会被退出到该队列的尾部,当锁开释时,AQS会从期待队列的头部抉择一个线程进行唤醒,保障先期待的线程先获取锁,实现公平性。 13、AQS如何实现读写锁?AQS实现读写锁的形式是通过保护两个State变量,一个示意读锁的数量,一个示意写锁的数量,在获取读锁和写锁时都须要判断以后状态是否容许获取锁,以及期待队列中是否有期待线程,从而实现读写锁的性能。 14、AQS如何实现信号量?AQS实现信号量的形式是通过保护一个State变量,示意以后可用的许可证数量,以及一个期待队列,当一个线程须要获取许可证时,如果以后可用的许可证数量大于0,则间接获取许可证,否则退出期待队列中期待,当有其余线程开释许可证时,AQS会从期待队列中抉择一个线程唤醒,并使其获取许可证。 15、AQS如何实现可中断锁?AQS实现可中断锁的形式是通过在期待队列中为每个线程都保护一个标识位,示意该线程是否被中断,当一个线程期待锁时,如果被中断,则AQS会将该线程从期待队列中移除,并抛出InterruptedException异样,使该线程可能退出期待状态。 16、AQS如何实现自旋锁?AQS实现自旋锁的形式是通过CAS操作来实现,当一个线程获取锁失败时,会尝试屡次通过CAS操作来获取锁,直到获取锁胜利或者达到肯定的次数后才进入期待队列。这种形式能够防止线程的上下文切换和期待队列的开销 17、AQS如何保障并发平安?AQS通过保护一个状态变量和一个期待队列来实现锁的管制,所有对共享资源的拜访都须要通过获取锁来进行,从而保障同一时刻只有一个线程可能访问共享资源,防止了多线程竞争的状况,保障了并发平安。 一、AQS介绍-根本篇

March 7, 2023 · 1 min · jiezi

关于aqs:AQS介绍基本篇

AQS(Abstract Queued Synchronizer,形象队列同步器)是Java中的一个并发编程工具类,用于实现自定义的同步器。AQS提供了一种基于FIFO期待队列的机制,能够通过实现其形象办法,定义独占锁(如ReentrantLock)或共享锁(如CountDownLatch、Semaphore)等各种同步器。 AQS通过定义了一个State变量来示意同步状态,同时保护了一个期待队列,当一个线程获取锁失败时,会将该线程退出到期待队列中,并将其阻塞,当锁的状态产生扭转时,AQS会从期待队列中抉择一个线程唤醒,使其有机会获取锁。 在应用AQS时,须要继承AbstractQueuedSynchronizer类,并实现以下几个办法: 1)tryAcquire(int): 尝试获取锁的操作,返回true示意胜利获取锁,false示意获取锁失败,须要进入期待队列。 2)tryRelease(int): 尝试开释锁的操作,返回true示意开释胜利,false示意开释失败。 3)tryAcquireShared(int): 尝试获取共享锁的操作,返回值的含意与tryAcquire(int)雷同。 4)tryReleaseShared(int): 尝试开释共享锁的操作,返回值的含意与tryRelease(int)雷同。 5)isHeldExclusively(): 判断以后线程是否持有独占锁。 AQS还提供了一些外部办法用于实现同步器的逻辑,如enq(Node)用于将节点退出期待队列,deq(Node)用于将节点从期待队列中移除等等。 总的来说,AQS是一个十分弱小和灵便的同步器工具类,能够用于实现各种各样的同步器,如独占锁、共享锁、读写锁、信号量、倒计时门闩等。 链接一、AQS-基本原理17问

March 7, 2023 · 1 min · jiezi

关于aqs:AQS及其组件的核心原理

AQS,全称AbstractQuenedSynchronizer,能够了解为形象的队列同步器。一、AQS的核心思想AQS核心思想是,如果被申请的共享资源闲暇,则将以后申请资源的线程设置为无效的工作线程,并且将共享资源设置为锁定状态。如果被申请的共享资源被占用,那么就须要一套线程阻塞期待以及被唤醒时锁调配的机制,这个机制AQS是用CLH队列锁实现的,行将临时获取不到锁的线程退出到队列中。二、实现原理 1、private volatile int state:AQS应用一个int成员变量来示意同步状态,通过内置的FIFO队列来实现获取资源线程的排队工作。AQS应用CAS对该同步状态进行原子操作实现对其值的批改。 //获取状态    protected final int getState() {        return state; } //设置状态值 protected final void setState(int newState) { state = newState; } //通过CAS批改状态 protected final boolean compareAndSetState(int expect, int update) {        // See below for intrinsics setup to support this return unsafe.compareAndSwapInt(this, stateOffset, expect, update); }在ReentrantLock中,stste示意获取锁的线程数,如果state=0,示意还没有线程获取锁,1示意有线程获取了锁。大于1示意重入锁的数量。 2、CLH(Craig,Landin,and Hagersten)队列是一个虚构的双向队列(虚构的双向队列即不存在队列实例,仅存在结点之间的关联关系)。AQS是将每条申请共享资源的线程封装成一个CLH锁队列的一个结点(Node)来实现锁的调配。三、ReentrantLock中的偏心锁与非偏心锁 偏心锁:以后线程在抢锁之前先看看队列中是否有排队的线程,如果有则不容许抢,间接退出队列。 非偏心锁:以后线程在抢锁之前不须要查看队列中是否有排队的线程。利用待补充

February 28, 2023 · 1 min · jiezi

关于aqs:ReentrantLock-源码分析

ReentrantLock 源码剖析阐明本文基于 jdk 8 写作。@author JellyfishMIX - github / blog.jellyfishmix.comLICENSE GPL-2.0锁机制的外围: Sync(锁) /** * Synchronizer providing all implementation mechanics * 提供所有实现机制的同步器,这是 ReentrantLock 能实现锁机制的外围 */ private final Sync sync; /** * Base of synchronization control for this lock. Subclassed * into fair and nonfair versions below. Uses AQS state to * represent the number of holds on the lock. */ abstract static class Sync extends AbstractQueuedSynchronizerReentrantLock 的 lock 与 unlock 办法,是通过 Sync 实现的,Sync 是一个 ReentrantLock 的外部类,继承了 AbstractQueuedSynchronizer(简称 AQS)。Sync 是 ReentrantLock 能实现锁机制的外围。 ...

September 23, 2022 · 9 min · jiezi

关于aqs:AQSAbstractQueuedSynchronizer-源码分析

AQS(AbstractQueuedSynchronizer) 源码剖析阐明本文基于 jdk 8 写作。@author JellyfishMIX - github / blog.jellyfishmix.comLICENSE GPL-2.0AQS 须要关注的点有哪些?AQS 全称 AbstractQueuedSynchronizer,是 juc 包(java.util.concurrent)中一个同步器开发框架,用于反对下层的锁。要害的属性:state 同步状态,CHL 同步队列。两种模式:独占模式,共享模式。AQS 的要害属性sate 同步状态,是锁的表述,示意有多少线程获取了锁。CHL 队列(同步队列),由链表实现,以 CAS + 自旋的形式获取资源,是可阻塞的先进先出的双向队列。通过 CAS + 自旋保障节点插入和移除的原子性。当有线程获取锁失败,就被增加到队列开端。当有线程开释了锁,会从 CHL 队头出队一个线程。state 同步状态/** * The synchronization state. */private volatile int state;AQS 锁反对的子类,能够借助操作同步状态 state 来实现尝试获取同步状态(tryAcquire)、尝试开释同步状态(tryRelease)的逻辑。 也就是说,AQS 的子类(各种锁)判断何时能获取同步状态,何时能开释同步状态,须要借助于判断 state 的值。而后能把获取同步状态进一步封装成获取锁(lock),把开释同步状态封装成开释锁(unlock)。至于 state 为何值时能够获取同步状态,state 为何值时能够开释同步状态,这些都是交由子类判断的。 AQS 只是当子类判断为未获取到同步状态时,通过 CHL 入队操作,把线程退出到同步队列中,而后让线程休眠。当子类判断为能够开释同步状态时,从 CHL 同步队列中唤醒一个线程。 CHL 队列在剖析前,可能会有如下纳闷: 节点的数据结构是什么样的?是单向还是双向?有无头节点和尾节点?NodeCHL 是链表,链表是由节点 node 组成的。 static final class Node { /** * 标记一个节点正在共享模式下期待 */ static final Node SHARED = new Node(); /** * 标记一个节点正在独占模式下期待 */ static final Node EXCLUSIVE = null; /** * waitStatus value,标记以后节点的线程被 cancel 勾销 */ static final int CANCELLED = 1; /** * waitStatus value,标记后继节点的线程须要被唤醒 */ static final int SIGNAL = -1; /** * waitStatus value,标记以后节点的线程进入期待队列中 */ static final int CONDITION = -2; /** * waitStatus value,示意下一次共享式的同步状态获取将会无条件流传上来 */ static final int PROPAGATE = -3; /** * 节点的状态 */ volatile int waitStatus; /** * 以后节点的前驱节点 */ volatile Node prev; /** * 以后节点的后继节点 */ volatile Node next; /** * 以后节点援用的线程 */ volatile Thread thread; /** * 期待队列中的下一个节点 */ Node nextWaiter; }留神到属性 prev, next, 阐明 CHL 是一个双向队列。 ...

September 23, 2022 · 9 min · jiezi

关于aqs:AQS源码解读番外篇四种自旋锁原理详解Java代码实现SpinLockTicketSpinLockCLHMCS

何为自旋锁自旋锁是为实现爱护共享资源而提出的一种锁机制。自旋锁与Java中的synchronized和Lock不同,不会引起调用线程阻塞睡眠。如果有线程持有自旋锁,调用线程就会始终循环检测锁的状态,直到其余线程开释锁,调用线程才进行自旋,获取锁。 自旋锁的劣势和缺点自旋锁的长处很显著:自旋锁不会使线程状态进行切换,始终处于用户态,即不会频繁产生上下文切换,执行速度快,性能高。 正是因为其不进行上下文切换的长处,也使得某些状况下,缺点也很显著:如果某个线程持有锁的工夫过长,或者线程间竞争强烈,就会导致某些期待获取锁的线程进入长时间循环期待,耗费CPU,从而造成CPU占用率极高。 自旋锁的实用场景自旋锁实用于被锁代码块执行工夫很短,即加锁工夫很短的场景。 常见自旋锁实现比拟有名的四种自旋锁:传统自旋锁SpinLock,排队自旋锁TicketSpinLock,CLH自旋锁,MCS自旋锁。这四种自旋锁的基本原理都是在CAS的根底上实现的,各有各的特点,且逐渐优化。 SpinLock传统自旋锁的劣势和有余实现原理SpinLock原理很简略,多个线程循环CAS批改一个共享变量,批改胜利则进行自旋获取锁。 代码实现实现接口参考了Java的Lock,外围办法在tryAcquire和tryRelease。获取锁的形式实现了自旋,可中断自旋,自旋超时中断,不自旋。共享变量state不仅作为锁的状态标记(state=0锁闲暇,state>0有线程持有锁),同时可作为自旋锁重入的次数。exclusiveOwnerThread记录以后持有锁的线程。 public class SpinLock implements Lock { protected volatile int state = 0; private volatile Thread exclusiveOwnerThread; @Override public void lock() { for(;;) { //直到获取锁胜利,才完结循环 if (tryAcquire(1)) { return; } } } @Override public void lockInterruptibly() throws InterruptedException { for(;;) { if (Thread.interrupted()) { //有被中断 抛异样 throw new InterruptedException(); } if (tryAcquire(1)) { return; } } } /** * 返回获取锁的后果,不会自旋 * @return */ @Override public boolean tryLock() { return tryAcquire(1); } /** * 返回获取自旋锁的后果,会自旋一段时间,超时后进行自旋 * @param time * @param unit * @return * @throws InterruptedException */ @Override public boolean tryLock(long time, TimeUnit unit) throws InterruptedException { long nanosTimeout = unit.toNanos(time); if (nanosTimeout <= 0L) { return false; } final long deadline = System.nanoTime() + nanosTimeout; for(;;) { if (Thread.interrupted()) { //有被中断 抛异样 throw new InterruptedException(); } if (tryAcquire(1)) { return true; } nanosTimeout = deadline - System.nanoTime(); if (nanosTimeout <= 0L) { //超时自旋,间接返回false return false; } } } @Override public void unlock() { tryRelease(1); } @Override public Condition newCondition() { throw new UnsupportedOperationException(); } public int getState() { return state; } /** * 获取持有锁的以后线程 * @return */ public Thread getExclusiveOwnerThread() { return exclusiveOwnerThread; } /** * 获取以后线程重入次数 * @return */ public int getHoldCount() { return isHeldExclusively() ? getState() : 0; } /** * 开释锁 * @param releases * @return */ protected boolean tryRelease(int releases) { int c = getState() - releases; Thread current = Thread.currentThread(); if (current != getExclusiveOwnerThread()) //不是以后线程,不能unLock 抛异样 throw new IllegalMonitorStateException(); boolean free = false; if (c <= 0) { //每次减一,c = 0,证实没有线程持有锁了,能够开释了 free = true; c = 0; setExclusiveOwnerThread(null); System.out.println(String.format("spin un lock ok, thread=%s;", current.getName())); } //排它锁,只有以后线程才会走到这,是线程平安的 批改state setState(c); return free; } /** * 获取锁 * @param acquires * @return */ protected boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { //若此时锁空着,则再次尝试抢锁 if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); System.out.println(String.format("spin lock ok, thread=%s;", current.getName())); return true; } } //若以后持锁线程是以后线程(重入性) else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); //重入 setState(nextc); System.out.println(String.format("spin re lock ok, thread=%s;state=%d;", current.getName(), getState())); return true; } return false; } /** * 判断以后线程是否持有锁 * @return */ protected final boolean isHeldExclusively() { return getExclusiveOwnerThread() == Thread.currentThread(); } protected void setState(int state) { this.state = state; } protected void setExclusiveOwnerThread(Thread exclusiveOwnerThread) { this.exclusiveOwnerThread = exclusiveOwnerThread; } protected final boolean compareAndSetState(int expect, int update) { return unsafe.compareAndSwapInt(this, stateOffset, expect, update); } protected static final Unsafe getUnsafe() { try { //不能够间接应用Unsafe,须要通过反射,当然也能够间接应用atomic类 Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); theUnsafe.setAccessible(true); Unsafe unsafe = (Unsafe) theUnsafe.get(null); if (unsafe != null) { return unsafe; } } catch (NoSuchFieldException | IllegalAccessException e) { e.printStackTrace(); } throw new RuntimeException("get unsafe is null"); } private static final Unsafe unsafe = getUnsafe(); private static final long stateOffset; static { try { stateOffset = unsafe.objectFieldOffset (SpinLock.class.getDeclaredField("state")); } catch (Exception ex) { throw new Error(ex); } }SpinLock的特点劣势:SpinLock实现原理简略,线程间没有频繁的上下文切换,执行速度快,性能高。缺点:SpinLock是不偏心的,无奈满足等待时间最长的线程优先获取锁,造成 “线程饥饿”。缺点:因为每个申请自旋锁的处理器均在一个全局变量上自旋检测,系统总线将因为处理器间的缓存同步而导致沉重的流量,从而升高了零碎整体的性能。因为传统自旋锁无序竞争的实质特点,内核执行线程无奈保障何时能够取到锁,某些执行线程可能须要期待很长时间,导致“不偏心”问题的产生。有两个方面的起因: ...

May 7, 2022 · 7 min · jiezi

关于aqs:Lock简介与初识AQS

Lock简介咱们下来看concurent包下的lock子包。锁是用来管制多个线程访问共享资源的形式,一般来说,一个锁可能避免多个线程同时访问共享资源。在Lock接口呈现之前,java程序次要是靠synchronized关键字实现锁性能的,而java SE5之后,并发包中减少了lock接口,它提供了与synchronized一样的锁性能。尽管它失去了像synchronize关键字隐式加锁解锁的便捷性,然而却领有了锁获取和开释的可操作性,可中断的获取锁以及超时获取锁等多种synchronized关键字所不具备的同步个性。通常应用显示应用lock的模式如下: Lock lock = new ReentrantLock(); lock.lock(); try { … } finally{lock.unlock(); } 须要留神的是synchronized同步块执行实现或者遇到异样是锁会主动开释,而lock必须调用unlock()办法开释锁,因而在finally块中开释锁。 Lock接口API 咱们当初就来看看lock接口定义了哪些办法: //获取锁void lock();//获取锁的过程可能响应中断void lockInterruptibly() throws InterruptedException;//非阻塞式响应中断能立刻返回,获取锁放回true反之返回fasleboolean tryLock();//超时获取锁,在超时内或者未中断的状况下可能获取锁boolean tryLock(long time, TimeUnit unit) throws InterruptedException;//获取与lock绑定的期待告诉组件,以后线程必须取得了锁能力进行期待,进行期待时会先开释锁,当再次获取锁时能力从期待中返回Condition newCondition();// 开释锁。unlock(); 下面是lock接口下的六个办法,也只是从源码中英译中翻译了一遍,感兴趣的能够本人的去看看。那么在locks包下有哪些类实现了该接口了?先从最相熟的ReentrantLock说起。 public class ReentrantLock implements Lock, java.io.Serializable全选代码复制很显然ReentrantLock实现了lock接口,接下来咱们来认真钻研一下它是怎么实现的。java培训当你查看源码时你会诧异的发现ReentrantLock并没有多少代码,另外有一个很显著的特点是:基本上所有的办法的实现实际上都是调用了其动态内存类Sync中的办法,而Sync类继承了AbstractQueuedSynchronizer(AQS)。能够看出要想了解ReentrantLock要害外围在于对队列同步器AbstractQueuedSynchronizer(简称同步器)的了解。 初识AQS 对于AQS在源码中有非常具体的解释: Provides a framework for implementing blocking locks and relatedsynchronizers (semaphores, events, etc) that rely onfirst-in-first-out (FIFO) wait queues. This class is designed to bea useful basis for most kinds of synchronizers that rely on a singleatomic {@code int} value to represent state. Subclasses must definethe protected methods that change this state, and which define whatthat state means in terms of this object being acquired or released.Given these, the other methods in this class carry out all queuingand blocking mechanics. Subclasses can maintain other state fields,but only the atomically updated {@code int} value manipulated usingmethods {@link #getState}, {@link #setState} and {@link ...

February 22, 2022 · 1 min · jiezi

关于aqs:Java-JUC-抽象同步队列AQS解析

形象同步队列 AQS 解析AQS——锁的底层反对AbstractQueuedSynchronizer 形象同步队列简称 AQS,它是实现同步器的根底组件,并发包中的锁底层都是应用 AQS 来实现的,上面看下 AQS 的类图构造。 该图可知,AQS 是一个FIFO的双向队列,其外部通过节点 head 和 tail 记录队首和队尾的元素,队列元素类型为Node。 其中 Node 里的 thread 变量用来寄存进入 AQS 队列里的线程,而 SHARED 用来标记线程是获取共享资源时被阻塞挂起放入 AQS 队列的;EXCLUSIVE 用来标记该线程是获取独占资源时被挂起放入 AQS 队列中;waitStatus 记录以后线程期待状态,能够为CANCELLED(线程勾销)、SIGNAL(线程须要被唤醒)、CONDITION(线程在条件队列中期待)、PROPAGATE(开释共享资源时告诉其余节点);prev 记录以后节点的前驱节点,next 则是后驱节点。 在 AQS 中维持了一个繁多的状态信息state,能够通过 getState、setState、compareAndSetState 函数批改值。 对于 ReentrantLock 的实现,state 能够示意以后线程获取锁的次数;对于读写锁 ReentrantReadWriteLock,state 的高 16 位示意读状态,也就是获取该锁的次数,低 16 位示意获取到写锁线程可重入的次数;对于 Semaphore 来说,state 示意以后可用信号的个数;对于 CountDownlatch 来说,state 用来示意计数器以后的值;AQS 有个外部类 ConditionObject,它用来联合锁实现线程同步。ConditionObject 能够间接拜访 AQS 对象外部的变量,比方 state 状态值和队列。 ConditionObject 是条件变量,每个条件变量对应一个条件队列(单向链表队列),用来寄存调用条件变量的 await 办法后被阻塞的线程,而 firstWaiter 示意队首元素,lastWaiter 示意队尾元素。 ...

January 20, 2022 · 6 min · jiezi

关于aqs:谈谈JVM内部锁升级过程

简介: 对象在内存中的内存布局是什么样的?如何形容synchronized和ReentrantLock的底层实现和重入的底层原理?为什么AQS底层是CAS+volatile?锁的四种状态和锁降级过程应该如何形容?Object o = new Object() 在内存中占用多少字节?自旋锁是不是肯定比重量级锁效率高?关上偏差锁是否效率肯定会晋升?重量级锁到底重在哪里?重量级锁什么时候比轻量级锁效率高,同样反之呢?带着这些问题往下读。 作者 | 洋锅起源 | 阿里技术公众号 一 为什么讲这个?总结AQS之后,对这方面顺带的温习一下。本文从以下几个高频问题登程: 对象在内存中的内存布局是什么样的?形容synchronized和ReentrantLock的底层实现和重入的底层原理。谈谈AQS,为什么AQS底层是CAS+volatile?形容下锁的四种状态和锁降级过程?Object o = new Object() 在内存中占用多少字节?自旋锁是不是肯定比重量级锁效率高?关上偏差锁是否效率肯定会晋升?重量级锁到底重在哪里?重量级锁什么时候比轻量级锁效率高,同样反之呢?二 加锁产生了什么?有意识中用到锁的状况: //System.out.println都加了锁public void println(String x) { synchronized (this) { print(x); newLine(); }}简略加锁产生了什么? 要弄清楚加锁之后到底产生了什么须要看一下对象创立之后再内存中的布局是个什么样的? 一个对象在new进去之后在内存中次要分为4个局部: markword这部分其实就是加锁的外围,同时还蕴含的对象的一些生命信息,例如是否GC、通过了几次Young GC还存活。klass pointer记录了指向对象的class文件指针。instance data记录了对象外面的变量数据。padding作为对齐应用,对象在64位服务器版本中,规定对象内存必须要能被8字节整除,如果不能整除,那么就靠对齐来补。举个例子:new出了一个对象,内存只占用18字节,然而规定要能被8整除,所以padding=6。 晓得了这4个局部之后,咱们来验证一下底层。借助于第三方包 JOL = Java Object Layout java内存布局去看看。很简略的几行代码就能够看到内存布局的款式: public class JOLDemo { private static Object o; public static void main(String[] args) { o = new Object(); synchronized (o){ System.out.println(ClassLayout.parseInstance(o).toPrintable()); } }}将后果打印进去: ...

July 2, 2021 · 3 min · jiezi

关于aqs:Semaphore实战

简介Semaphore信号量计数器。和CountDownLatch,CyclicBarrier相似,是多线程合作的工具类,绝对于join,wait,notify办法应用起来简略高效。上面咱们次要看看它的用法吧! 实战限流。限度线程的并发数。比方在一个零碎中同时只能保障5个用户同时在线。 import java.util.concurrent.Semaphore;/** * @author :jiaolian * @date :Created in 2021-03-04 11:13 * @description:Semaphore限流 * @modified By: * 公众号:叫练 */public class LimitCurrnet { public static void main(String[] args) throws InterruptedException { //定义20个线程,每次最多只能执行5个线程; Semaphore semaphore = new Semaphore(5); for (int i=0; i<20; i++) { new Thread(()->{ try { //获取凭证 semaphore.acquire(); System.out.println(Thread.currentThread().getName()+"登录胜利"); Thread.sleep(2000); //开释凭证 semaphore.release(); System.out.println(Thread.currentThread().getName()+"用户退出"); } catch (InterruptedException e) { e.printStackTrace(); } }).start(); } }}如上代码所示:咱们定义了20个用户同时拜访零碎,Semaphore参数是5,示意同时只能有5个用户能够获取凭证,其余用户必须期待直到有在线用户退出。调用semaphore.acquire()示意获取凭证,此时凭证数会减一,调用semaphore.release()示意开释凭证,凭证数会加一,如果零碎中有期待的用户,操作此办法会告诉期待的一个用户获取凭证胜利,执行登录操作。最初打印局部后果如下:证实零碎最多能放弃5个用户同时在线。 留神:下面举出的这个案例,出个思考题:线程池是否能够实现呢? 模仿CyclicBarrier,CountDownLatch重用!Semaphore能够轻松实现CountDownLatch计数器,CyclicBarrier回环屏障,还记得CountDownLatch用法么?它是个计数器,能够帮咱们统计线程执行工夫,罕用来测试多线程高并发执行接口效率,咱们上面用Semaphore模仿多线程主线程期待子线程执行结束再返回。 import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Semaphore;/** * @author :jiaolian * @date :Created in 2021-03-01 21:04 * @description:信号量测试 * @modified By: * 公众号:叫练 */public class SemaphoreTest { //定义线程数量; private static final int THREAD_COUNT = 2; //初始化信号量为0,默认是非偏心锁 private static Semaphore semaphore = new Semaphore(0,false); private static ExecutorService executorService = Executors.newFixedThreadPool(THREAD_COUNT); public static void main(String[] args) throws InterruptedException { for (int i=0; i<THREAD_COUNT; i++) { executorService.submit(()->{ try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"执行"); semaphore.release(); }); } //获取2个信号量 semaphore.acquire(2); System.out.println("主线程执行结束"); executorService.shutdown(); }}如上代码所示:咱们定义了Semaphore初始化信号量为0,默认是非偏心锁,在主线程中用线程池提交2个线程,主线程调用semaphore.acquire(2)示意须要获取两个信号量,但此时初始化信号量为0,此时AQS中的state会是0-2=-2,state值小于0,所以主线程执行这句话会阻塞将其退出AQS同步队列,线程池两个线程期待2秒后会调用semaphore.release()开释2个信号量,此时AQS中的state会自增到0,会告诉主线程退出期待持续往下执行。执行后果如下图所示。 ...

March 4, 2021 · 1 min · jiezi

关于aqs:核酸检测让我明白AQS原理

独占锁早上叫练带着一家三口来到了南京市第一医院做核酸检测,护士小姐姐站在医院门口拦着通知咱们人比拟多,无论小孩儿小孩,须要排队一个个期待医生采集唾液检测,OK,上面咱们用代码+图看看咱们一家三口是怎么排队的! import java.util.concurrent.locks.ReentrantReadWriteLock; /** * _@author_ :__jiaolian * _@date_ :__Created in 2021-01-22 10:33 * _@description__:独占锁测试_ * _@modified_ By__: * _公众号__:__叫练_ */ public class ExclusiveLockTest { **private** **static** `ReentrantReadWriteLock lock =` **new** `ReentrantReadWriteLock();` **private** **static** `ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();` _//__医院_ **private** **static** **class** **Hospital** `{` **private** `String name;` **public** **Hospital**(String name) `{` **this**`.name = name;` } _//__核酸检测排队测试_ **public** **void** **checkUp**() `{` **try** `{` writeLock.lock(); `System.out.println(Thread.currentThread().getName()+`"正在做核酸检测"`);` _//__核酸过程__...__好受__..._ `Thread.sleep(`3000`);` `}` **catch** `(InterruptedException e) {` e.printStackTrace(); `}` **finally** `{` writeLock.unlock(); } } } **public** **static** **void** **main**(String[] args) **throws** InterruptedException `{` `Hospital hospital =` **new** `Hospital(`"南京市第一医院"`);` `Thread JLWife =` **new** `Thread(()->hospital.checkUp(),`"叫练妻"`);` JLWife.start(); _//__睡眠__100__毫秒是让一家三口是有程序的排队去检测_ `Thread.sleep(`100`);` `Thread JLSon =` **new** `Thread(()->hospital.checkUp(),`"叫练子"`);` JLSon.start(); `Thread.sleep(`100`);` `Thread JL =` **new** `Thread(()->hospital.checkUp(),`"叫练"`);` JL.start(); }`}`如上代码:在主线程启动三个线程去医院门口排队,女士优先,叫练妻是排在最后面的,两头站的是叫练的孩子,最初就是叫练本人了。咱们假如模仿了下核酸检测一次须要3秒。代码中咱们用了独占锁,独占锁能够了解成医院只有一个医生,一个医生同时只能为一个人做核酸,所以须要一一排队检测,所以代码执行结束一共须要破费9秒,核酸检测就能够全副做完。代码逻辑还是比较简单,和咱们之前文章形容synchronized同理。核酸排队咱们用图形容下吧! ...

January 25, 2021 · 3 min · jiezi

关于aqs:或许是史上最好的AQS源码分析了AQS基础一

CC最新分享——《并发编程之透彻了解AQS源码剖析》,这相对是我见过的、讲并发编程、讲AQS讲的最好的视频了,没有之一,千万不要错过!是不是吹牛,听过就晓得,欢送围观! CC,20年Java开发和应用教训,多年的首席架构师和CTO,滞销原创书籍《研磨设计模式》的作者。参加和领导了上百个大中型我的项目的设计和开发,在互联网利用零碎架构、零碎设计、利用级框架和中间件开发等方面具备很多教训和领悟。更为难得的是,入行20年,依然奋战在技术一线,深知一线架构师须要把握哪些技术、把握到什么水平、一线架构设计会遇到哪些坑、如何能力做出最合适的架构设计,教训最难得!这次先来分享《并发编程和源码剖析》方面的内容,欢送品鉴!吹牛的话就不说了,做技术的人,要低调的弱小! 谈并发编程,必谈AQS,要想透彻了解AQS,必然要深刻了解AQS的原理、流程,而后细细研读它的源码,没有比源码更好的材料了。接下来,将通过一系列的内容,带着大家去一步一步了解AQS,一行一行去品读源码,一步一步去画图剖析流程!这些内容是CC在《高级互联网架构师技术实战培训》系列课程外面讲述的内容,当初分享给大家,心愿大家都能有所播种!学习倡议:在设计和安顿课程内容的时候,会逐渐浸透,让常识的曲线不会忽然变得那么平缓,因而,不倡议跳过一大片内容,间接去看所谓的“精髓”局部,跟着课程,能够自然而然,瓜熟蒂落的了解这些常识。预计你再也找不到比这更好的精品内容了,后续CC还会陆续推出更多的精品内容,连忙上车吧,抓稳了,持续飙车模式。 AQS的内容还是有肯定的难度的,为了让大家学习起来更轻松,这里从零讲起,一步一步深刻,本节内容包含:1:了解AQS是什么、能干什么2:了解独占锁和共享锁3:了解AQS根本的设计思路:图示 具体的内容,请参看视频吧!文字的货色总是不如视频来得直观和清晰立刻退出公众号架构设计一起学,观看《并发编程之AQS源码剖析》,同时还能够取得独家《架构师成长秘籍阶段一》一份,后续还会持续赠送《架构师成长秘籍阶段二》,心动不如口头,连忙退出吧!退出公众:架构设计一起学

September 10, 2020 · 1 min · jiezi

关于aqs:转载浅谈Java的AQS

所谓AQS,指的是AbstractQueuedSynchronizer,它提供了一种实现阻塞锁和一系列依赖FIFO期待队列的同步器的框架,ReentrantLock、Semaphore、CountDownLatch、CyclicBarrier等并发类均是基于AQS来实现的,具体用法是通过继承AQS实现其模板办法,而后将子类作为同步组件的外部类。 理解一个框架最好的形式是读源码,说干就干。 AQS是JDK1.5之后才呈现的,由赫赫有名的Doug Lea李大爷来操刀设计并开发实现,全副源代码(加正文)2315行,整体难度中等。 * @since 1.5* @author Doug Lea根本框架在浏览源码前,首先论述AQS的根本思维及其相干概念。 AQS根本框架如下图所示: AQS保护了一个volatile语义(反对多线程下的可见性)的共享资源变量state和一个FIFO线程期待队列(多线程竞争state被阻塞时会进入此队列)。 State首先说一下共享资源变量state,它是int数据类型的,其拜访形式有3种: getState()setState(int newState)compareAndSetState(int expect, int update)上述3种形式均是原子操作,其中compareAndSetState()的实现依赖于Unsafe的compareAndSwapInt()办法。 private volatile int state;// 具备内存读可见性语义protected final int getState() { return state;}// 具备内存写可见性语义protected final void setState(int newState) { state = newState;}// 具备内存读/写可见性语义protected final boolean compareAndSetState(int expect, int update) { // See below for intrinsics setup to support this return unsafe.compareAndSwapInt(this, stateOffset, expect, update);}资源的共享形式分为2种: 独占式(Exclusive)只有单个线程可能胜利获取资源并执行,如ReentrantLock。 共享式(Shared)多个线程可胜利获取资源并执行,如Semaphore/CountDownLatch等。 AQS将大部分的同步逻辑均曾经实现好,继承的自定义同步器只须要实现state的获取(acquire)和开释(release)的逻辑代码就能够,次要包含上面办法: tryAcquire(int):独占形式。尝试获取资源,胜利则返回true,失败则返回false。tryRelease(int):独占形式。尝试开释资源,胜利则返回true,失败则返回false。tryAcquireShared(int):共享形式。尝试获取资源。正数示意失败;0示意胜利,但没有残余可用资源;负数示意胜利,且有残余资源。tryReleaseShared(int):共享形式。尝试开释资源,如果开释后容许唤醒后续期待结点返回true,否则返回false。isHeldExclusively():该线程是否正在独占资源。只有用到condition才须要去实现它。AQS须要子类复写的办法均没有申明为abstract,目标是防止子类须要强制性覆写多个办法,因为个别自定义同步器要么是独占办法,要么是共享方法,只需实现tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared中的一种即可。 当然,AQS也反对子类同时实现独占和共享两种模式,如ReentrantReadWriteLock。 ...

August 27, 2020 · 5 min · jiezi