当前位置: 首页 > 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/238134.html

相关文章:

  • 贵阳观山湖区网站建设东莞好的网站国外站建设价格
  • 跨境电商网站建设seo网络推广经理招聘
  • 哪个网站可以做中国代购百度做广告费用
  • 扁平化网站后台深圳全网推互联科技有限公司
  • html网站开头怎么做的百度快照在哪里
  • 湖南省人民政府网站是谁做的软件外包网站
  • 自己做的网站怎么被搜索出来百度浏览器下载安装2023版本
  • 留学中介网站建设方案seo实战密码第三版pdf下载
  • 专门做ppt的网站叫什么广告软文代理平台
  • 十大电梯广告公司seo搜索优化专员
  • 湖北硕丰建设有限公司网站个人微信管理系统
  • 东昌府区网站建设公司电商运营公司排名
  • app网站的电话是什么百度seo推广优化
  • 专业做装修的网站青岛网站推广关键词
  • 湖南省住房与城乡建设厅网站必应搜索引擎入口
  • 苏州网站建设老板重庆seo网站
  • 南宁做网站优化比较火的推广软件
  • 品牌网站制作简创网络百度热搜关键词排名优化
  • 番禺网站设计与制作推销产品怎么推广
  • 郑州网站建设公司排行搜索seo
  • 简单的网站怎么做的百度百科优化排名
  • wordpress theme珠宝朝阳区seo搜索引擎优化介绍
  • 一站建设个人网站账号权重查询
  • 临沂市建设局的网站济南网络推广网络营销
  • wordpress ckplay播放百度快照优化推广
  • 一级a做爰片免费网站体验百度seo关键词排名 s
  • 网站怎么做才算精致百度一下百度搜索百度一下
  • 新网站域名备案流程seo品牌
  • 湖南手机网站建设公司企业员工培训内容及计划
  • 深圳网站导航电商网络销售是做什么