2019独角兽企业重金招聘Python工程师标准>>>

一、线程同步

线程同步是指两个并发执行的线程在同一时间不同时执行某一部分的 程序。同步问题在生活中也很常见,就比如在麦当劳点餐,假设只有一个服务员能够提供点餐服务。每个服务员在同一时刻只能接待一个顾客的点餐,那么除了正在 接待的顾客,其他人只能等待排队。当一个点餐服务完成之后,其他顾客就可以上去进行点餐。

从这个例子中可以看到如下几个关注点:

点餐服务为临界区域(critical area),其可同时进行的数量,即为有多少人可进入临界区域。

排队即为对目前暂时无法取得点餐服务的人的一种处理方式。这种处理方式的特性有公平性(按次序),效率性(接手最快为最好)等。

顾客进行排队和从队伍中叫一个顾客来进行服务即为睡眠(park)和唤醒(unpark)机制

并发中线程同步是重点需关注的问题,线程同步自然也有一定的模式,DougLea就写出了一个简单的框架AQS用来支持一大类线程同步工具,如ReentrantLock,CountdownLatch,Semphaore等。

AQS是concurrent包中的一系列同步工具的基础实现,其提供了状态位,线程阻塞-唤醒方法,CAS操作。基本原理就是根据状态位来控制线程的入队阻塞、出队唤醒来解决同步问题。

入队:

出队:

二、代码分析

下面以ReentrantLock来说明AQS的组成构件的工作情况:

在ReentrantLock中封装了一个同步器Sync,继承 了AbstractQueuedSynchronizer,根据对临界区的访问的公平性要求不同,又分为NonfairSync和FairSync。为了 简化起见,就取最简单的NonFairSync作为例子来说明:

1. 对于临界区的控制:

java.util.concurrent.locks.ReentrantLock.NonfairSync

final void lock() {2:  3:         if (compareAndSetState(0, 1))4:  5:         setExclusiveOwnerThread(Thread.currentThread());6:  7:         else8:  9:         acquire(1);10:  11:     }

从以上代码可以看出,其主要目的是采用cas比较临界区的状态。

1.1. 如果为0,将其设置为1,并记录当前线程(当前线程可进入临界区);

1.2. 如果为1,尝试获取临界区控制

java.util.concurrent.locks.AbstractQueuedSynchronizer

public final void acquire(int arg) {2:  3:             if (!tryAcquire(arg) &&4:  5:                 acquireQueued(addWaiter(Node.EXCLUSIVE), arg))6:  7:                 selfInterrupt();8:  9:           }

1.2.1. NonFairLock的tryAcquire实现为:

final boolean nonfairTryAcquire(int acquires) {2:  3:               final Thread current = Thread.currentThread();4:  5:               int c = getState();6:  7:               if (c == 0) {8:  9:               if (compareAndSetState(0, acquires)) {10:  11:                  setExclusiveOwnerThread(current);12:  13:                  return true

上述代码主要是针对大部分线程进入临界区工作时间不会很长而进行的性能优化,第一次尝试失败了,极有可能过一会儿锁就释放了,因此重新去尝试获取锁。

1.2.2. 以下这段代码是锁的精华部分

java.util.concurrent.locks.AbstractQueuedSynchronizer

for (;;) {8:  9: final Node p = node.predecessor();10:  11: if (p == head && tryAcquire(arg)) {12:  13: setHead(node);14:  15: p.next = null; // help GC16:  17: return interrupted;18:  19: }

在无限循环中完成了对线程的阻塞和唤醒。阻塞在parkAndCheckInterrupt()唤醒后从此处进行释放。

算法过程:

从加入队列的node开始反向查找,将前一个元素赋值给p;

如果p是head,那么试着再获得一次锁tryAcquire(arg),成功则将head指针往后移动,并跳出循环;

如果上一步骤尝试失败,那么进行测试是否要park ,如果状态为0,将其标记为SIGNAL,并返回false;

再重复检查一次,发现其头部的waitStatus为-1.Node.signal。确认需要park successor; 进行parkAndCheckInterrupt()将当前线程阻塞。

2. 对于临界区的释放

2.1. java.util.concurrent.locks.AbstractQueuedSynchronizer

public final boolean release(int arg) {2:  3: if (tryRelease(arg)) {4:  5: Node h = head;6:  7: if (h != null && h.waitStatus != 0)8:  9: unparkSuccessor(h);10:  11: return true;12:  13: }return false;16:  17: }

2.1.1. java.util.concurrent.locks.ReentrantLock.Sync

protected final boolean tryRelease(int releases) {2:  3: int c = getState() - releases;4:  5: if (Thread.currentThread() != getExclusiveOwnerThread())6:  7: throw new IllegalMonitorStateException();8:  9: boolean free = false;10:  11: if (c == 0) {12:  13: free = true;14:  15: setExclusiveOwnerThread(null);16:  17: }18:  19: setState(c);20:  21: return free;22:  23: }24:

将state进行变化-releases,检查当前线程是否是拿住锁的线程,否则掷出异常.如果为0,将持有锁线程标记为null。

从ReentrantLock例子可以看出AQS的工作原理,更为精妙的是,在这几个基本机制作用下衍生了许多种并发工具,以后的介绍中可以看到。

转载于:https://my.oschina.net/lonelyzero/blog/352346

Java线程同步之一--AQS相关推荐

  1. java线程 同步与异步 线程池

    1)多线程并发时,多个线程同时请求同一个资源,必然导致此资源的数据不安全,A线程修改了B线 程的处理的数据,而B线程又修改了A线程处理的数理.显然这是由于全局资源造成的,有时为了解 决此问题,优先考虑 ...

  2. (转) Java线程同步阻塞, sleep(), suspend(), resume(), yield(), wait(), notify()

    为了解决对共享存储区的访问冲突,Java 引入了同步机制.但显然不够,因为在任意时刻所要求的资源不一定已经准备好了被访问,反过来,同一时刻准备好了的资源也可能不止一个. 为解决访问控制问题,Java ...

  3. 关于java线程同步的笔记_线程同步(JAVA笔记-线程基础篇)

    在多线程应用程序中经常会遇到线程同步的问题.比如:两个线程A.线程B可能会 "同时" 执行同一段代码,或修改同一个变量.而很多时候我们是不希望这样的. 这时候,就需要用到线程同步. ...

  4. java线程同步——条件对象+synchronized 关键字

    [0]README 0.1) 本文描述转自 core java volume 1, 源代码为原创,旨在理解 java线程同步--条件对象+synchronized 关键字 的相关知识: 0.2)for ...

  5. java线程同步——竞争条件的荔枝+锁对象

    [0]README 0.1) 本文描述转自 core java volume 1, 源代码为原创,旨在理解 java线程同步--竞争条件的荔枝+锁对象 的相关知识: 0.2) for full sou ...

  6. Java线程同步-模拟买票

    文章首发于 2020-11-29 知乎文章:Java线程同步-模拟买票 作者:落雨湿红尘(也是我o) 01 导语 本文使用JAVA代码模拟买票场景下的业务交互,通过示例讲解线程的初始化.线程同步等ja ...

  7. Java --- 线程同步和异步的区别

    1. Java 线程 同步与异步 多线程并发时,多个线程同时请求同一个资源,必然导致此资源的数据不安全,A线程修改了B线程的处理的数据,而B线程又修改了A线程处理的数理.显然这是由于全局资源造成的,有 ...

  8. Java线程同步的几种方式

    Java线程同步的几种方式 1.使用synchronized关键字  它的工作是对同步的代码加锁,使得每一次只能有一个线程进入同步块,从而保证线程间的安全性.  synchronized关键字的用法: ...

  9. java线程同步原理

    一. java线程同步原理 java会为每个object对象分配一个monitor,当某个对象的同步方法(synchronized methods)被多个线程调用时,该对象的monitor将负责处理这 ...

  10. Java线程--同步和异步的区别

    本文转自https://blog.csdn.net/u011033906/article/details/53840525 1. Java 线程 同步与异步 多线程并发时,多个线程同时请求同一个资源, ...

最新文章

  1. linux系统盘使用率达到100%的问题查找和解决方法
  2. VTK:绘图之ParallelCoordinates
  3. 四则运算题目生成程序
  4. 下拉多选择框 实现方式_物体检测之旅(三)|设计选择,经验教训和物体检测的趋势...
  5. 一文理清Cookie、Session、Token
  6. 让一个从未接触过电脑的人测试浏览器
  7. 你不知道的outerText,innerText
  8. 计算机网络工程概论论文,网络工程专业导论论文提纲格式模板 网络工程专业导论论文框架怎么写...
  9. java实现思维导图_Java并发(思维导图)
  10. 从冬奥会看中国科技:全民感谢的高速摄像机,有何玄机?
  11. 【转帖】文件系统驱动编程基础篇
  12. 计算机控制键功能,电脑ctrl键的作用大全
  13. 我的世界服务器文件翻译,我的世界server.properties翻译 联机参数设置攻略
  14. 友谊的小船,说翻就翻
  15. 动漫插画培训班有哪些
  16. Apache报错指定的网络名不再可用解决方案
  17. 使用sendmail发送email
  18. mybatis 易百练习笔记
  19. 2021届前端秋招经验分享(最终拿下拼多多、美团、京东offer)
  20. 武田呈报的ALK+ NSCLC长期数据显示,ALUNBRIG(R) (brigatinib)在2年随访期之后继续展示一线治疗中的优效性

热门文章

  1. day12-html(css)
  2. 祝刘冬冬十八周岁快乐
  3. 合肥赛区结束,继续训练提升
  4. Web 开发与设计师速查手册大全
  5. 树链剖分【p3038】[USACO11DEC]牧草种植Grass Planting
  6. mysql自增字段重排 或 归零
  7. 设计一个简易的有道词典
  8. 使用ODBC API读取Decimal或者Numeric
  9. opencv 获取图像最大连通域 c++和python版
  10. Creative Groove Randomizer插件:Audiomodern Playbeat节拍生成器