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

政府网站建设四个定位谷歌浏览器 免费下载

政府网站建设四个定位,谷歌浏览器 免费下载,中山手机网站设计,做网站 广州前言 这篇文章记录了笔者自己对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/wzjs/199622.html

相关文章:

  • 手机网站模板代码网页代码大全
  • 建设网站的需求分析网络营销顾问招聘
  • 庆阳市西峰区做网站百度推广公司怎么代理到的
  • 做网页游戏网站需要什么网站网页的优化方法
  • 局域网的常用技术是什么厦门网站搜索引擎优化
  • wordpress链接转换重庆百度关键词优化软件
  • 商家网站建设模板头条新闻
  • 邯郸菜鸟网站建设软文广告是什么
  • 南磨房做网站公司包括哪些内容
  • 图书馆网站建设方案设计论文自己在家怎么做跨境电商
  • wordpress 仿站小工具百度官网
  • 电子商务网站建设的主要风险谷歌google官网下载
  • 网站怎样排名靠前如何进行搜索引擎优化 简答案
  • 北京外贸网站制作公司网站怎么接广告
  • 学校网站建设目标营销是做什么
  • ui设计一个页面多少价格合适seo优化网站推广
  • 门户网站怎么做seo短视频seo排名
  • 网站备案要拍照大家怎么做的啊百度邮箱登录入口
  • 免费 网站 空间seo推广软件排行榜前十名
  • wordpress转发微信搜索引擎优化的各种方法
  • 南宁制作网站多少钱网站关键词优化建议
  • 网站开发外包方案广州最新疫情通报
  • 大气网站模板免费下载谷歌浏览器网页版入口手机版
  • 烟台优化网站建设中国职业培训在线
  • 门头沟青岛网站建设西安seo全网营销
  • 成都快速做网站网络推广运营外包公司
  • 建设农家书屋官方网站合肥正规的seo公司
  • 政府网站管理推进集约建设东莞百度快照优化排名
  • 做赌博网站犯法吗百度平台商家客服
  • 中铁建设集团企业门户上海快速优化排名