类继承关系:

NonfairSync => Sync => AbstractQueuedSynchronizer

类NonfairSync

final void lock() {

if (compareAndSetState(0, 1))

setExclusiveOwnerThread(Thread.currentThread());

else

acquire(1);

}

分析:

compareAndSetState(0, 1):通过cas操作更新state状态,若成功,则获取到锁,否则,进行排队申请操作acquire

类AbstractQueuedSynchronizer

public final void acquire(int arg) {

if (!tryAcquire(arg) &&

acquireQueued(addWaiter(Node.EXCLUSIVE), arg))

selfInterrupt();

}

分析:

tryAcquire方法最终实现为:

类Sync

final boolean nonfairTryAcquire(int acquires) {

final Thread current = Thread.currentThread();

int c = getState();

if (c == 0) {

if (compareAndSetState(0, acquires)) {

setExclusiveOwnerThread(current);

return true;

}

}

else if (current == getExclusiveOwnerThread()) {

int nextc = c + acquires;

if (nextc < 0) // overflow

throw new Error("Maximum lock count exceeded");

setState(nextc);

return true;

}

return false;

}

通过cas操作更新state状态,若成功,则获取到锁,否则,首先进行排队,

类AbstractQueuedSynchronizer

private Node addWaiter(Node mode) {

Node node = new Node(Thread.currentThread(), mode);

// Try the fast path of enq; backup to full enq on failure

Node pred = tail;

if (pred != null) {

node.prev = pred;

if (compareAndSetTail(pred, node)) {

pred.next = node;

return node;

}

}

enq(node);

return node;

}

注意:

每一个线程被封装成一个Node节点。

进入enq方法——入队列

private Node enq(final Node node) {

for (;;) {

Node t = tail;

if (t == null) { // Must initialize

if (compareAndSetHead(new Node()))

tail = head;

} else {

node.prev = t;

if (compareAndSetTail(t, node)) {

t.next = node;

return t;

}

}

}

}

分析:

这里针对head和tail属性的赋值均为cas原子操作。

最终模型如图:

如果多线程并发入队,最终结果如图:

注:prev和next分别为Node类的两个属性

入队操作结束后,开始请求队列acquireQueued

类AbstractQueuedSynchronizer

final boolean acquireQueued(final Node node, int arg) {

boolean failed = true;

try {

boolean interrupted = false;

for (;;) {

final Node p = node.predecessor();

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

setHead(node);

p.next = null; // help GC

failed = false;

return interrupted;

}

if (shouldParkAfterFailedAcquire(p, node) &&

parkAndCheckInterrupt())

interrupted = true;

}

} finally {

if (failed)

cancelAcquire(node);

}

}

分析:

  1. Node p = node.predecessor()获取node的prev节点
  2. 如果prev==head节点并且tryAcquire返回true,则更新head节点为当前节点,并退出循环,也就获取到了锁。
  3. 否则的话,执行shouldParkAfterFailedAcquire和parkAndCheckInterrupt。
  4. setHead方法来修改head属性,改变队列的头部节点

  其中,shouldParkAfterFailedAcquire方法是针对waitStatus属性的修改

  private final boolean parkAndCheckInterrupt() {

  LockSupport.park(this);

  return Thread.interrupted();

  }

  LockSupport.park(this),使当前线程进入阻塞。

unlock分析

类AbstractQueuedSynchronizer

public final boolean release(int arg) {

if (tryRelease(arg)) {

Node h = head;

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

unparkSuccessor(h);

return true;

}

return false;

}

类Sync

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;

setExclusiveOwnerThread(null);

}

setState(c);

return free;

}

分析:

主要工作就是设置还原state状态

类AbstractQueuedSynchronizer

private void unparkSuccessor(Node node) {

int ws = 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);

}

分析:

  1. 入参node即head节点
  2. Node s = node.next;即获取到下一个节点,即正在阻塞中的线程
  3. LockSupport.unpark(s.thread);即激活线程

分析NonfairSync加锁/解锁过程的更多相关文章

  1. 从ReentrantLock加锁解锁角度分析AQS

    本文用于记录在学习AQS时,以ReentrantLock为切入点,深入源码分析ReentrantLock的加锁和解锁过程. 同步器AQS的主要使用方式是继承,子类通过继承同步器并实现它的抽象方法来管理 ...

  2. 进程间通信(IPC)+进程加锁解锁

    [0]README 0.1) source code and text description are from orange's implemention of a os: 0.2) for com ...

  3. Spring Ioc源码分析系列--Bean实例化过程(一)

    Spring Ioc源码分析系列--Bean实例化过程(一) 前言 上一篇文章Spring Ioc源码分析系列--Ioc容器注册BeanPostProcessor后置处理器以及事件消息处理已经完成了对 ...

  4. 多线程与高并发(二)—— Synchronized 加锁解锁流程

    前言 上篇主要对 Synchronized 的锁实现原理 Monitor 机制进行了介绍,由于 Monitor 基于操作系统调用,上下文切换导致开销大,在竞争不激烈时性能不算很好, 在 jdk6 之后 ...

  5. Linux第三周——跟踪分析内核的启动过程

    跟踪分析内核的启动过程实验 张潇月<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 这周主要学习的是对内核 ...

  6. Linux 进程与线程四(加锁--解锁)

    线程共享进程的内存空间,打开的文件描述符,全局变量. 当有多个线程同事访问一块内存空间或者一个变量.一个文件描述符,如果不加控制,那么可能会出现意想不到的结果. 原子操作 对于我们的高级语言(C语言, ...

  7. 使用redis的比较完美的加锁解锁

    使用redis的比较完美的加锁解锁 tags:redis read&write redis加锁和解锁 php 习惯性说一下写这篇文章要说明什么,我们经常用redis进行加锁操作,目的是为了解决 ...

  8. MyBatis 源码分析 - SQL 的执行过程

    * 本文速览 本篇文章较为详细的介绍了 MyBatis 执行 SQL 的过程.该过程本身比较复杂,牵涉到的技术点比较多.包括但不限于 Mapper 接口代理类的生成.接口方法的解析.SQL 语句的解析 ...

  9. MyBatis 源码分析 - 映射文件解析过程

    1.简介 在上一篇文章中,我详细分析了 MyBatis 配置文件的解析过程.由于上一篇文章的篇幅比较大,加之映射文件解析过程也比较复杂的原因.所以我将映射文件解析过程的分析内容从上一篇文章中抽取出来, ...

随机推荐

  1. 【Java】Java批量文件打包下载zip

    网上看了很多,本文使用ant.jar中的org.apache.tools.zip,页面用js表单提交 代码供参考: ACTION: /*      * 另存为      */     @Request ...

  2. POJ3258--River Hopscotch(Binary Search similar to POJ2456)

    Every year the cows hold an event featuring a peculiar version of hopscotch that involves carefully ...

  3. HDU2444 The Accomodation of Students

    The Accomodation of Students Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K ( ...

  4. ZUFE2486 Heap 2017-05-31 14:37 41人阅读 评论(0) 收藏

    2486: Heap 时间限制: 2 Sec  内存限制: 128 MB 提交: 16  解决: 5 [提交][状态][讨论版] 题目描述 有n个非负整数,a1,a2,a3.....an. 有Q次询问 ...

  5. codeforces 925 c big secret

    题意: 给你n个数,b[1],b[2],b[3].......,让你重新排列,使a[i]的值递增 a[i]和b的关系: a[i] = b[1]^b[2]^b[3]^....^b[i]; 首先说异或   ...

  6. floyd算法之最小环问题

    最小环问题:都比较容易得到从u 到 v 经过中间某一些结点的最短路,但是我们得确保回来的时候,不能经过那些结点,这样我们就需要改一下floyd算法了 进而我们想到用Floyd算法.我们知道,Floyd ...

  7. DDL和DML的区别

    DML(data Manipulation Language)数据库操纵语言: 使用范围:对数据库中的数据进行一些简单的操作,如IDUS(增删改查) DDL(Data Definiton Langua ...

  8. android根据图片路径显示图片

    首先根据图片路径先创建一个文件path为图片路径:然后判断文件是否存在,如果存在,将图片显示出来. File file = new File(path); ImageView img = (Image ...

  9. hive函数 get_json_object的使用

    hive提供了json的解析函数:get_json_object 使用方法 对于jsonArray(json数组),如person表的xjson字段有数据: [{"name":&q ...

  10. Android-WebView加载网络图片&网页

    加载网络图片: 链接地址:  http://bcs.link-us.com.cn/directBank/newHX149/directBank/h5/www/dist/img/e113.jpg 确保链 ...