当前位置: 首页 > news >正文

学院的网站建设的意义作品展示的网站

学院的网站建设的意义,作品展示的网站,线上运营推广工作内容,可以做淘宝客的网站有哪些前言 这篇文章记录了笔者自己对FutureTask的部分源码设计的思考与心得,属于笔者自己的观点,若有哪位热爱源码研究的同仁觉得我说的不对,欢迎批评指正。 提示:在阅读之前必须对FutureTask的源码和实现原理有一定的了解。本文要聊…

前言

这篇文章记录了笔者自己对FutureTask的部分源码设计的思考与心得,属于笔者自己的观点,若有哪位热爱源码研究的同仁觉得我说的不对,欢迎批评指正。

提示:在阅读之前必须对FutureTask的源码和实现原理有一定的了解。本文要聊的内容在FutureTask中awaitDone方法之中。

FutureTask中awaitDone方法的源码

在FutureTask源码中,awaitDone方法的作用是“Awaits completion or aborts on interrupt or timeout.”,即等待任务完成,或者在中断或超时的时候终止。其用于FutureTask的阻塞式获取任务执行结果的get()方法之中,如果在某线程调用FutureTask的get()方法获取任务执行结果,但是任务还没执行完成,则使用awaitDone方法将该线程阻塞。

因为可能不止一个线程去调用get()方法被阻塞,所以FutureTask将所有阻塞等待的线程封装成WaitNode节点,然后使用一个栈来存储这些WaitNode节点。

/*
*  timed:是否定时等待,即等待是否有超时时间
*  nanos:如果是定时等待,此参数是等待的时间
*/
private int awaitDone(boolean timed, long nanos)throws InterruptedException {//如果等待有超时时间,计算等待的截止时间final long deadline = timed ? System.nanoTime() + nanos : 0L;//用于封装等待线程的WaitNode节点WaitNode q = null;//节点是否入栈boolean queued = false;//开启循环for (;;) {//如果线程被中断if (Thread.interrupted()) {//从栈中移除当前线程的WaitNode节点,并且抛出中断异常removeWaiter(q);throw new InterruptedException();}//获取当前任务的状态int s = state;//任务已经结束了(正常完成、抛出异常、被取消)则返回stateif (s > COMPLETING) {if (q != null)q.thread = null;return s;}//如果任务即将完成,让其他线程先执行else if (s == COMPLETING) // cannot time out yetThread.yield();//如果任务没有完成,也不处于即将完成的中将状态COMPLETING,则进入自旋//第一次循环,如果当前WitNode为null,创建一个WaitNode结点else if (q == null)q = new WaitNode();//第二次循环,如果当前WaitNode节点没有入队,则尝试入队else if (!queued)queued = UNSAFE.compareAndSwapObject(this, waitersOffset,q.next = waiters, q);//第三次循环,根据是否有超时时间来挂起线程else if (timed) {//计算当前时间离超时时间点还有的时间差nanos = deadline - System.nanoTime();//超出了指定时间,就移除当前节点并返回任务状态if (nanos <= 0L) {removeWaiter(q);return state;}//挂起线程(有超时时间)LockSupport.parkNanos(this, nanos);}else//挂起线程LockSupport.park(this);}}

用流程图演示心中的疑问

下面,我将awaitDone方法的执行流程画图表示,再谈我先前对awaitDone方法执行流程的疑问。
在这里插入图片描述

在上面的流程图之中,有一点让我最初感觉很奇怪,那就是在执行“创建节点和”和“节点入栈”之后,为什么不接着走下面的流程,而是回到最上面的判断“线程是否中断”这一步骤?这样不是多次一举,去多执行两次无意义的循环吗?

我以前认为,正确的流程应该是这样的。如果判断未创建节点,则先创建节点,然后继续执行“判断节点是否入栈”后续步骤;如果判断节点未入栈,则先执行节点入栈,然后继续执行判断是否定时等待后续步骤。这样的设计似乎让程序更加高效。

下面画出我先前认为更加合理的流程图,红色方框内是变化的内容。
在这里插入图片描述

用自旋锁解释awaitDone方法的流程设计

自旋锁是什么

刚开始,我任务这是JDK源码的缺陷。后来我随着知识面的扩展,我了解到有一种锁叫做“自旋锁”。

先看自旋锁的概念解释:

自旋锁是为高效并发而产生的一种锁优化的思想,要实现线程互斥同步往往需要对某些线程进行阻塞,而线程的挂起和恢复都要转入到内核态去完成。作为Java程序员,笔者也不太懂什么是内核态,但是需要知道的是线程的挂起和恢复是一种重量级的操作,也就是比较消耗CPU性能。
如果共享数据的锁定时间很短,那么为了这很短的时间去进行挂起和恢复线程这个重量级操作就划不来。对于多核CPU来说,可以多个线程并行,让需要请求锁的线程“稍等一下”比直接阻塞要好得多,这样线程大概率可以在等待中获取其他线程释放的锁,就不用放弃CPU的执行时间。
于是产生了自旋锁,自旋锁就是为了让线程等待获取锁而让线程去执行一个有限的循环,这种循环又叫做线程的自旋。

自旋锁思想的体现

从自旋锁思想来看,awaitDone方法中多执行的两次循环并不是无意义的,也不是编码上的缺陷,而是刻意为之。

线程在进入阻塞之前的两次多余的循环,是为了等待任务执行结束而进行的自旋,也就是应用了自旋锁的思想。因为线程的阻塞和重启是比较消耗性能的重量级操作,所以JDK源码中尽量做到能不阻塞线程就不阻塞,故意让线程多进行了两次循环(自旋),为任务执行结束而“稍等一下”,如果两次自旋还等不来任务完成,再阻塞线程

这也是为什么将FutureTask将任务状态细分为COMPLETING(即将结束)和NORMAL(正常结束)的原因,如果任务已经执行完成,但是还没有给返回结果赋值,就将任务状态设为COMPLETING,好让需要获取执行结果的线程知道任务已经快要结束了,可以使用Thread.yield()暂时让出CPU时间片,稍等片刻后就能直接获取到结果而不用阻塞。一切设计都体现了能不阻塞就不阻塞的思想。

http://www.dtcms.com/a/547787.html

相关文章:

  • 第1063章 自己做视频网站陕西网站建设公司电话
  • 站酷的网址网页小游戏在线玩知乎
  • 做网站一定需要icp么企业品牌策划排行榜
  • 网站互联互联网舆情监测系统
  • 自助建站网站如何下载wordpress
  • 有没有专门招代理的网站上海网站公司建设
  • 如何建立属于自己的网站潍坊知名网站建设
  • 青岛网络建站公司用自己的计算机做服务器建网站
  • 新网站为什么做的这么难罗湖实惠的网站建设费用
  • 给我一个网站图片网站设计和平面设计
  • 网站建设需要准备什么建网站做站长怎么赚钱
  • 个人网站 平台有没有专门做网站的
  • 做网站要分几部分完成在线看国内永久免费crm
  • dw做网站简单首页wordpress js加载位置
  • 怎么创建网站详细流程seo公司中国
  • 学做网站需要什么软件o2o商城系统
  • 巫山网站建设3小时网站建设平台
  • 代做毕设要注册答疑网站萍乡企业网站制作
  • php做网站标题加链接传动设备 技术支持 东莞网站建设
  • 网站设计目的苏州手机网站建设公司
  • 传奇辅助网站怎么建设dede 汽车网站
  • 工商注册在哪个网站公司网络搭建
  • 英国男女做那个视频网站百度权重9的网站
  • 宇宙企画网站wordpress很强大
  • 用php做购物网站h5怎么制作的
  • 陶瓷刀具网站策划书网站正在维护模板
  • 深圳市住房和建设局网站和市住宅租赁管理服务中心商城网站建设技术论坛
  • 如何制作境外网站新网 如何建设网站
  • 小游戏网站怎么做搜索引擎优化的流程
  • 比较知名的企业微信小程序排名关键词优化