`
哎喔别走
  • 浏览: 4860 次
  • 性别: Icon_minigender_1
  • 来自: 上海
最近访客 更多访客>>
社区版块
存档分类
最新评论

java并发AQS原理之ReentrantLock

    博客分类:
  • java
阅读更多

 

看本文建议结合源码

 

首先来看看ReentrantLock的构造方法,它的构造方法有两个,如所示:

public ReentrantLock() {

    sync = new NonfairSync();

}

public ReentrantLock(booleanfair) {

    sync = fair ? new FairSync() : new NonfairSync();

}

ReentrantLock中定义了三个内部类,分别是Sync以及Sync的子类FairSyncNonfairSync,分别实现了公平策略和非公平策略,默认实现的是非公平策略。

 

公平和非公平的第一个区分点,首先来看NonfairSynclock方法

finalvoid lock() {

    if (compareAndSetState(0, 1))

         setExclusiveOwnerThread(Thread.currentThread());

    else

         acquire(1);

}

假设有三个并发的线程,第一个线程调用lock的时候,compareAndSetState(0,1)是可以正常执行的返回true,然后把当前线程置为独占模式的当前所有者,然后该线程可以执行后续操作。如果第二个线程被放到队列中,第三个线程走到compareAndSetState(0,1),第一个线程刚好unlock掉,那么第三个线程就会直接执行,而不是等待第二个线程执行后,这也就是非公平模式的特点。第二个线程调用lock的时候,compareAndSetState(0,1)返回false,执行acquire(1),该方法会调用tryAcquire(1)acquireQueued(addWaiter(Node.EXCLUSIVE), 1)

先来看下tryAcquire(1),该方法的实现是nonfairTryAcquire方法,代码如下:

finalboolean nonfairTryAcquire(intacquires) {

    final Thread current = Thread.currentThread();

    intc = getState();

    if (c == 0) {

        if (compareAndSetState(0, acquires)) {

            setExclusiveOwnerThread(current);

            returntrue;

        }

    }

    elseif (current == getExclusiveOwnerThread()) {

        intnextc = c + acquires;

        if (nextc < 0) // overflow

            thrownew Error("Maximum lock count exceeded");

        setState(nextc);

        returntrue;

    }

    returnfalse;

}

看代码,结合三个线程并发的场景,第一个线程lock后,会把state(默认值是0)的值置为1,所以c的值现在是1getExclusiveOwnerThread()是第一个线程,所以直接返回false,执行acquireQueued(addWaiter(Node.EXCLUSIVE), 1),方法addWaiter(Node.EXCLUSIVE)的作用是根据给的排他模式把当前线程(也就是第二个线程)加入队列中,此时的队列情况如下:

 

首次有线程(Node)进入队列时,会先new一个Node对象作为头部,然后把首次进队列的线程(Node)挂在其后面。Node对象是包含当前线程和模型的作为队列元素

然后执行acquireQueued(final Node node, int arg),来看下代码:

finalboolean acquireQueued(final Node node, intarg) {

    booleanfailed = true;

    try {

        booleaninterrupted = false;

        for (;;) {

            final Node p = node.predecessor();

            if (p == head && tryAcquire(arg)) {

                setHead(node);

                p.next = null; // help GC

                failed = false;

                returninterrupted;

            }

            if (shouldParkAfterFailedAcquire(p, node) &&

                parkAndCheckInterrupt())

                interrupted = true;

        }

    } finally {

        if (failed)

            cancelAcquire(node);

    }

}

第二个线程入队列,前面是一个初始化的对象也是head的值,进入循环后,会再次tryAcquire(1),假设依然获取不到,则进入第二个if语句中,执行shouldParkAfterFailedAcquire(p, node)方法和parkAndCheckInterrupt()方法,parkAndCheckInterrupt()就会把第二个线程阻塞起来。

 

公平和非公平的第二个区分点在tryAcquire(int acquires)方法中,如下:

protectedfinalboolean tryAcquire(intacquires) {

    final Thread current = Thread.currentThread();

    intc = getState();

    if (c == 0) {

        if (!hasQueuedPredecessors() &&

            compareAndSetState(0, acquires)) {

            setExclusiveOwnerThread(current);

            returntrue;

        }

    }

    elseif (current == getExclusiveOwnerThread()) {

        intnextc = c + acquires;

        if (nextc < 0)

            thrownew Error("Maximum lock count exceeded");

        setState(nextc);

        returntrue;

    }

    returnfalse;

}

当第一个线程走完,第二个线程在队列中,第三个线程调用acquire(int arg)时先调用tryAcquire方法,会进行!hasQueuedPredecessors() && compareAndSetState(0, acquires)判断,而非公平的只有进行了compareAndSetState(0, acquires)判断,不考虑队列是否有等待的线程,而hasQueuedPredecessors()该方法就是判断队列中是否有阻塞的线程,如果有返回true,然后执行acquireQueued方法入队列。在第三个线程入队列同时,第一个线程走完调用unlock操作,该操作就会去调用release方法,如下

publicfinalboolean release(intarg) {

    if (tryRelease(arg)) {

        Node h = head;

        if (h != null && h.waitStatus != 0)

            unparkSuccessor(h);

        returntrue;

    }

    returnfalse;

}

最终调用unparkSuccessor(h)方法,

privatevoid unparkSuccessor(Node node) {

    intws = node.waitStatus;

    if (ws < 0)

        compareAndSetWaitStatus(node, ws, 0);

    Node s = node.next;

    if (s == null || s.waitStatus > 0) {

        s = null;

        for (Node t = tail; t != null && t != node; t = t.prev)

            if (t.waitStatus <= 0)

                s = t;

    }

    if (s != null)

        LockSupport.unpark(s.thread);

}

 

从队列中获取第二个线程,unpark操作。阻塞结束后还在acquireQueued(final Node node, intarg)的循环体中,此时!hasQueuedPredecessors()compareAndSetState(0, acquires)都为true,并把当前线程置为独占模式的当前所有者,然后该线程可以执行程序中lock()方法的后续操作。

  • 大小: 1.6 KB
分享到:
评论

相关推荐

    Java并发之AQS详解.pdf

    Java并发之AQS详解 AbstractQueuedSynchronizer(AQS)是 Java 并发编程中的一个核心组件,提供了一套多线程访问共享资源的同步器框架。AQS 定义了两种资源共享方式:Exclusive(独占)和 Share(共享)。在 AQS 中...

    7、深入理解AQS独占锁之ReentrantLock源码分析(1).pdf

    通过对AQS和ReentrantLock的学习,我们了解到它们是Java并发编程中非常重要的组成部分。AQS作为底层框架,为多种同步器提供了统一的实现方案;而ReentrantLock则是在AQS基础上实现了高级锁的功能,使得开发者可以更...

    【并发编程】简单化理解AQS和ReentrantLock.pdf

    AQS和`ReentrantLock`是Java并发编程中重要的组成部分,通过对它们的理解和掌握,可以更好地设计和实现高性能的并发程序。通过本文的学习,读者可以了解到这些核心概念和技术的实际应用,并能够根据具体的业务需求...

    Java并发系列之ReentrantLock源码分析

    Java并发系列之ReentrantLock源码分析 ReentrantLock是Java 5.0中引入的一种新的加锁机制,它实现了Lock接口,并提供了与synchronized相同的互斥性和内存可见性。ReentrantLock的底层实现是通过AQS来实现多线程同步...

    Java并发 结合源码分析AQS原理

    AQS在Java并发编程中有广泛的应用,如ReentrantLock、CountDownLatch、Semaphore等。这些类都是通过继承AQS实现的,它们使用AQS提供的状态变量和队列来实现同步功能。 CountDownLatch的实现机制 CountDownLatch是...

    Java并发编程全景图.pdf

    Java并发编程是Java语言中最为复杂且重要的部分之一,它涉及了多线程编程、内存模型、同步机制等多个领域。为了深入理解Java并发编程,有必要了解其核心技术点和相关实现原理,以下将详细介绍文件中提及的关键知识点...

    JAVA并发编程与高并发解决方案-并发编程四之J.U.C之AQS.docx

    ### JAVA并发编程与高并发解决方案-并发编程四之J.U.C之AQS #### 引言 《JAVA并发编程与高并发解决方案-并发编程四之J.U.C之AQS》是一篇详细介绍Java实用并发工具包(Java Util Concurrency,简称J.U.C.)中重要...

    基于JDK源码解析Java领域中的并发锁之设计与实现.pdf

    在Java并发编程中,理解和掌握并发锁的原理与实现至关重要,因为它们是解决多线程环境下的互斥和同步问题的关键。本文将基于JDK源码解析Java领域中的并发锁,探讨AQS基础同步器、LockSupport、Condition接口、Lock...

    深入浅出_Java并发工具包原理讲解

    J.U.C提供了多种锁的实现,比如Lock接口及其实现ReentrantLock,提供了比synchronized更灵活的锁机制,同时AQS(AbstractQueuedSynchronizer)是实现各种锁的基础同步器,它管理着一系列的等待线程,并提供一种框架...

    java并发编程:juc、aqs

    理解并熟练掌握JUC和AQS对于Java并发编程至关重要,它们提供了强大且灵活的工具,可以有效解决多线程环境下的同步和通信问题,提高程序的性能和可扩展性。通过自定义AQS的子类,开发者可以根据实际需求构建出满足...

    Java并发编程学习笔记

    Java并发编程是Java开发中必不可少的一部分,涉及到多线程、同步机制、线程池以及并发工具类等多个核心知识点。以下是对这些主题的详细说明: 1. **线程安全与锁 Synchronized 底层实现原理**: 线程安全是指在多...

    图灵Java高级互联网架构师第6期并发编程专题笔记.zip

    04-Java并发线程池底层原理详解与源码分析-monkey 05-并发编程之深入理解Java线程-fox 06-并发编程之CAS&Atomic原子操作详解-fox 07-并发锁机制之深入理解synchronized(一)-fox 08-并发锁机制之深入理解...

    java并发之ReetranLock

    Java 并发之 ReentrantLock ReentrantLock 是 Java 并发包中的一个技术,在并发编程中非常常用。它是一个实现 Lock 接口的类,支持重入性,表示能够对共享资源能够重复加锁,即当前线程获取该锁再次获取不会被阻塞...

    java并发编程-AQS和JUC实战

    ### Java并发编程-AQS和JUC实战 #### 一、ReentrantLock 重入锁 **1.1 概述** - **基本介绍**: `ReentrantLock` 是一个实现了 `Lock` 接口的可重入互斥锁,提供比 `synchronized` 更丰富的功能。与 `synchronized...

    AQS的底层原理.zip

    在Java并发编程领域,AbstractQueuedSynchronizer(简称AQS)是一个核心组件,它是Java并发库中的基石,被许多并发工具类如ReentrantLock、Semaphore、CountDownLatch等作为基础框架来实现。AQS通过维护一个FIFO等待...

    Java中的显示锁ReentrantLock使用与原理详解

    Java中的显示锁ReentrantLock使用与原理详解 Java中的显示锁ReentrantLock是Java concurrency API中的一种同步机制,用于解决多线程安全问题。ReentrantLock是Java 5中引入的,它是一种可重入锁,允许同一个线程多...

    Java AQS详解.docx

    在Java并发编程中,如ReentrantLock、Semaphore和CountDownLatch等类的底层实现都离不开AQS。 **一、AQS概述** AQS 是一个抽象的队列同步器,它的核心是一个 volatile int 类型的 `state` 字段,表示资源的状态。...

    java并发之ASQ

    Java并发之ASQ,即AbstractQueuedSynchronizer(AQS),是Java并发编程中一个至关重要的技术,它为构建锁和其他同步组件提供了基础框架。AQS是一个抽象类,通过继承来实现具体的同步组件。虽然AQS本身并不实现任何...

    java并发编程面试题

    java并发编程 基础知识,守护线程与线程, 并行和并发有什么区别? 什么是上下文切换? 线程和进程区别 什么是线程和进程? 创建线程有哪几种方式?,如何避免线程死锁 线程的 run()和 start()有什么区别? 什么是 ...

Global site tag (gtag.js) - Google Analytics