CINXE.COM
理解Future及FutureTask的实现-腾讯云开发者社区-腾讯云
<!DOCTYPE html><html lang="zh" munual-autotracker-init="" qct-uid="" qct-pv-id="uPUIjE-rSXEfDBRMF3e2N" qct-ip="8.222.208.146"><head><meta charSet="UTF-8"/><meta http-equiv="X-UA-Compatible" content="IE=edge"/><meta name="format-detection" content="telephone=no"/><title>理解Future及FutureTask的实现-腾讯云开发者社区-腾讯云</title><meta name="subject" content="其他-空类-编程算法,通用技术-大数据技术-数据分析,通用技术-服务器技术-http,通用技术-前端开发-node.js"/><meta name="subjectTime" content="2020-08-17 10:41:44"/><meta name="articleSource" content="B"/><meta name="magicSource" content="N"/><meta name="authorType" content=""/><meta name="productSlug" content="tcap"/><meta name="keywords" content="编程算法,数据分析,http,node.js"/><meta name="description" content="Future是一种异步计算的模式,本文带你理解一下什么是Future,以及基本的FutureTask的实现原理。"/><meta property="og:title" content="理解Future及FutureTask的实现-腾讯云开发者社区-腾讯云"/><meta property="og:description" content="Future是一种异步计算的模式,本文带你理解一下什么是Future,以及基本的FutureTask的实现原理。"/><meta property="og:image" content="https://cloudcache.tencentcs.com/open_proj/proj_qcloud_v2/gateway/shareicons/cloud.png"/><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1, viewport-fit=cover"/><link rel="dns-prefetch" href="//qccommunity.qcloudimg.com"/><link rel="dns-prefetch" href="//ask.qcloudimg.com"/><link rel="dns-prefetch" href="//cloudcache.tencentcs.com"/><link rel="canonical" href="https://cloud.tencent.com/developer/article/1680378"/><meta name="next-head-count" content="20"/><link rel="stylesheet" href="https://imgcache.qq.com/open_proj/proj_qcloud_v2/gateway/portal/css/base.css"/><link rel="stylesheet" href="https://cloudcache.tencentcs.cn/qcloud/ui/cloud-community/build/base/base-202411191502.css"/><style type="text/css"> .rno-markdown p * { white-space: pre-wrap; word-break: break-all; } .tea-overlay { z-index: 99999!important; } </style><link rel="stylesheet" href="https://cloudcache.tencentcs.cn/qcloud/ui/cloud-community/build/Article/Article-202411141616.css"/><link rel="stylesheet" href="https://cloudcache.tencent-cloud.cn/qcloud/draft-master/dist/draft-master-v2.0.123.d4s2ddo9sb.css"/><link rel="stylesheet" href="https://qccommunity.qcloudimg.com/tc_player/release/tcplayer.min.css"/><script src="https://tam.cdn-go.cn/aegis-sdk/latest/aegis.min.js"></script><script> if (Aegis) { new Aegis({ id: 'dWlmyFvjDnalkbZO8q', env: 'production', onError: true, pagePerformance: true, reportAssetSpeed: true, api: { reportRequest: true, resHeaders: ['x-req-id'], }, reportApiSpeed: true, beforeRequest: function (data) { // load js failed if (data.logType === 'log') { if (data.logs.level === '32' && data.logs.msg.indexOf('google') > -1) return false; } var ignoreKeys = [ 'Script error', 'chrome-extension', 'qq.com', 'queryWeappQrcodeStatus', 'login/ajax/info', 'woa.com', 'trafficCollect.php', 'google', 'dscache', 'act-api', 'set_qc_cookie', 'opc.cloud.tencent.com', 'uc_gre_ad_buss', 'eb.xcj.pub', 'UCShellJava', '/developer/labs/quick/loader', 'edgeImmersiveReaderDOM', 'sendBeacon', 'error-decoder.html', 'qcloud-community-track.min.js' ]; var alarmMsg = [data.logs.url, data.logs.msg].join('|'); for (var i = 0; i < ignoreKeys.length; i++) { if (alarmMsg.indexOf(ignoreKeys[i]) != -1) return false; } if (/bot|wechatdevtools|spider/i.test(navigator.userAgent)) { return false; } if (location.hostname.indexOf('cloud.tencent.') === -1) { return false; } }, }); } </script><link rel="preload" href="https://qccommunity.qcloudimg.com/community/_next/static/css/15864e0bbdb1e0dc.css" as="style"/><link rel="stylesheet" href="https://qccommunity.qcloudimg.com/community/_next/static/css/15864e0bbdb1e0dc.css" data-n-g=""/><link rel="preload" href="https://qccommunity.qcloudimg.com/community/_next/static/css/ea44d1213c71c27d.css" as="style"/><link rel="stylesheet" href="https://qccommunity.qcloudimg.com/community/_next/static/css/ea44d1213c71c27d.css" data-n-p=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="https://qccommunity.qcloudimg.com/community/_next/static/chunks/polyfills-c67a75d1b6f99dc8.js"></script><script src="https://qccommunity.qcloudimg.com/community/_next/static/chunks/webpack-4b3f70494b513c95.js" defer=""></script><script src="https://qccommunity.qcloudimg.com/community/_next/static/chunks/framework-bae252e255276064.js" defer=""></script><script src="https://qccommunity.qcloudimg.com/community/_next/static/chunks/main-05fe3e9ebcc3b2a5.js" defer=""></script><script src="https://qccommunity.qcloudimg.com/community/_next/static/chunks/pages/_app-8122a2af2c111715.js" defer=""></script><script src="https://qccommunity.qcloudimg.com/community/_next/static/chunks/1001-2e1adf6d088ee502.js" defer=""></script><script src="https://qccommunity.qcloudimg.com/community/_next/static/chunks/900-71009a4f9d961db7.js" defer=""></script><script src="https://qccommunity.qcloudimg.com/community/_next/static/chunks/743-1dcf6b0fcebaa4b8.js" defer=""></script><script src="https://qccommunity.qcloudimg.com/community/_next/static/chunks/2191-2e402fdba497a1f2.js" defer=""></script><script src="https://qccommunity.qcloudimg.com/community/_next/static/chunks/9966-3be3b289121a48f8.js" defer=""></script><script src="https://qccommunity.qcloudimg.com/community/_next/static/chunks/552-eb32205d1d3e17d7.js" defer=""></script><script src="https://qccommunity.qcloudimg.com/community/_next/static/chunks/4031-e3e3905dc88f3f92.js" defer=""></script><script src="https://qccommunity.qcloudimg.com/community/_next/static/chunks/2391-e1b083c8280dce67.js" defer=""></script><script src="https://qccommunity.qcloudimg.com/community/_next/static/chunks/4117-79ab33e3944a99db.js" defer=""></script><script src="https://qccommunity.qcloudimg.com/community/_next/static/chunks/1200-586c8913d338875f.js" defer=""></script><script src="https://qccommunity.qcloudimg.com/community/_next/static/chunks/5305-6c6287588b89e496.js" defer=""></script><script src="https://qccommunity.qcloudimg.com/community/_next/static/chunks/9987-50fa00be52ea0a59.js" defer=""></script><script src="https://qccommunity.qcloudimg.com/community/_next/static/chunks/6995-71865d1b014e8b9a.js" defer=""></script><script src="https://qccommunity.qcloudimg.com/community/_next/static/chunks/9179-724eee5c06230b86.js" defer=""></script><script src="https://qccommunity.qcloudimg.com/community/_next/static/chunks/5039-d174dd09ec91e23e.js" defer=""></script><script src="https://qccommunity.qcloudimg.com/community/_next/static/chunks/4298-ecf78077c366b99e.js" defer=""></script><script src="https://qccommunity.qcloudimg.com/community/_next/static/chunks/787-c20307b99a7c9e79.js" defer=""></script><script src="https://qccommunity.qcloudimg.com/community/_next/static/chunks/6474-2c0e1629f7738528.js" defer=""></script><script src="https://qccommunity.qcloudimg.com/community/_next/static/chunks/5650-649e162b184be571.js" defer=""></script><script src="https://qccommunity.qcloudimg.com/community/_next/static/chunks/9626-02550f5f9bc8270d.js" defer=""></script><script src="https://qccommunity.qcloudimg.com/community/_next/static/chunks/3346-a1ce44eb71f29cdb.js" defer=""></script><script src="https://qccommunity.qcloudimg.com/community/_next/static/chunks/1794-4524fda45251d496.js" defer=""></script><script src="https://qccommunity.qcloudimg.com/community/_next/static/chunks/3270-57ce21952a43da02.js" defer=""></script><script src="https://qccommunity.qcloudimg.com/community/_next/static/chunks/8583-79f5e98099bd4de0.js" defer=""></script><script src="https://qccommunity.qcloudimg.com/community/_next/static/chunks/8876-194359d4cea91f27.js" defer=""></script><script src="https://qccommunity.qcloudimg.com/community/_next/static/chunks/pages/article/%5BarticleId%5D-df9140f92647ede0.js" defer=""></script><script src="https://qccommunity.qcloudimg.com/community/_next/static/A33mNyh0oM2Hz_SodWz7T/_buildManifest.js" defer=""></script><script src="https://qccommunity.qcloudimg.com/community/_next/static/A33mNyh0oM2Hz_SodWz7T/_ssgManifest.js" defer=""></script></head><body class=""><div id="__next"><script src="https://dscache.tencent-cloud.cn/ecache/qcstat/qcloud/qcloudStatApi.js"></script><script src="https://qccommunity.qcloudimg.com/common/exposure-plugin-4.1.15.min.js"></script><script src="https://qccommunity.qcloudimg.com/community-track/qcloud-community-track.min.js"></script><div class="cdc-responsive-layout" aegis-first-screen-timing="true" qct-area="文章详情页"><div class="cdc-article-page2 cdc-global"><div class="cdc-sticky-header mod-sticky-header is-hidden" style="left:0"><div id="community-top-header-product-container"></div><div class="cdc-sticky-header__inner"><div class="cdc-sticky-header__main"><div class="mod-sticky-header__main"><div class="mod-sticky-header__author"><span class="cdc-avatar circle"><a class="cdc-avatar__inner" style="background-image:url(https://ask.qcloudimg.com/avatar/1444933/q9xecryc4m.png)" href="/developer/user/1444933" target="_blank"></a></span><div class="author-info"><a class="author-info__name" href="/developer/user/1444933" target="_blank"><span class="name-text">Erwin</span></a></div></div><div class="mod-sticky-header__split"></div><div class="mod-sticky-header__title"><div class="mod-sticky-header__title-content"><h2 class="title-text">理解Future及FutureTask的实现</h2></div></div></div></div><div class="cdc-sticky-header__extra"><div class="mod-sticky-header__operates"><button class="cdc-btn mod-sticky-header__operate btn-focus cdc-btn--primary"><i class="add-icon"></i><span>关注作者</span></button></div></div></div></div><div class="cdc-m-guider-banner"><div class="cdc-m-guider-banner__guide-mvp is-detail-page"><div class="cdc-m-guider-banner__guide-mvp-text">前往小程序,Get<em>更优</em>阅读体验!</div><div class="cdc-m-guider-banner__guide-mvp-btn">立即前往</div></div></div><div class="cdc-header cdc-header--block" track="导航"><div class="cdc-header__placeholder"></div><div class="cdc-header__inner"><div id="community-top-header-product-container"></div><div class="cdc-header__top"><div class="cdc-header__top-left"><a href="/?from=20060&from_column=20060" target="_blank" class="cdc-header__top-logo" hotrep="" track="腾讯云官网入口"><i>腾讯云</i></a><div class="cdc-header__top-line"></div><a href="/developer" class="cdc-header__top-logo community"><i>开发者社区</i></a><div class="cdc-header__activity"><div id="cloud-header-product-container"></div></div></div><div class="cdc-header__top-operates"><a href="/document/product?from=20702&from_column=20702" target="_blank" class="cdc-header__link">文档</a><a href="/voc/?from=20703&from_column=20703" target="_blank" class="cdc-header__link">建议反馈</a><a href="https://console.cloud.tencent.com?from=20063&from_column=20063" target="_blank" class="cdc-header__link" track-click="{"areaId":102001,"subAreaId":1}">控制台</a><div class="cdc-header__account"><div class="cdc-header__account-inner"><button class="cdc-btn cdc-header__account-btn cdc-btn--primary">登录/注册</button></div></div></div></div><div class="cdc-header__bottom"><div class="cdc-header__bottom-nav"><a href="/developer" class="cdc-header__bottom-home">首页</a><div class="cdc-header__nav-list"><div class="cdc-header__nav-item">学习</div><div class="cdc-header__nav-item">活动</div><div class="cdc-header__nav-item">专区</div><div class="cdc-header__nav-item">工具</div></div><a href="/tvp?from=20154&from_column=20154" class="cdc-header__tvp" target="_blank">TVP</a><div class="cdc-header__activity"><a class="cdc-header__activity-tit" href="/act?from=20061&from_column=20061" target="_blank">最新优惠活动<div class="cdc-badge"><div class="cdc-badge-inner"><div class="cdc-badge-text"></div></div></div></a></div><div id="community-header-product-container"></div></div><div class="cdc-header__bottom-operates"><div class="cdc-header__search"><div class="cdc-search__wrap"><div class="cdc-search"><span class="cdc-search__text">文章/答案/技术大牛</span><button class="cdc-search__btn">搜索<i class="cdc-search__i search"></i></button></div><div class="cdc-search__dropdown"><div class="cdc-search__bar"><input type="text" class="cdc-search__bar-input" placeholder="文章/答案/技术大牛" value=""/><div class="cdc-search__bar-btns"><button class="cdc-search__btn">搜索<i class="cdc-search__i search"></i></button><button class="cdc-search__btn">关闭<i class="cdc-search__i clear"></i></button></div></div></div></div></div><div class="cdc-header__create"><span class="cdc-header__create-btn not-logged"><span class="cdc-svg-icon-con"><span class="cdc-svg-icon" style="width:16px;height:16px"><svg width="16" height="16" viewBox="0 0 16 16" fill="currentcolor" xmlns="http://www.w3.org/2000/svg"><path d="M14.2466 12.0145C14.1698 13.6258 12.8381 14.9131 11.2129 14.9131H11.1579H4.0927H4.03772C2.4125 14.9131 1.08014 13.6258 1.00334 12.0145H1V11.8668V4.07213V4.04627V3.89922H1.00334C1.08014 2.28732 2.4125 1 4.03772 1H9.6473V1.00069H10.0786L8.7688 2.10773H8.43888H7.7916H6.37904H4.03772C2.97234 2.10773 2.10445 2.9777 2.10445 4.04629V4.41869V4.4472V6.39498V11.4269V11.4309V11.8668C2.10445 12.9354 2.97234 13.8053 4.03772 13.8053H6.37904H8.87153H11.2129C12.2782 13.8053 13.1461 12.9355 13.1461 11.8668V11.466V11.454V9.5181V6.39364L14.2506 5.3051V11.8668V12.0145H14.2466ZM10.4324 7.15226L9.63146 7.99761C9.36577 8.2693 8.69326 8.95104 8.48066 9.17631C8.26726 9.40288 8.09039 9.58901 7.95061 9.73544C7.81079 9.88188 7.72667 9.96597 7.70083 9.98656C7.63321 10.0488 7.55703 10.1144 7.47022 10.1846C7.38412 10.2542 7.29404 10.3099 7.20063 10.3516C7.10722 10.4007 6.97072 10.459 6.79049 10.5305C6.61028 10.6001 6.42213 10.6676 6.22468 10.7339C6.02792 10.8002 5.84109 10.8571 5.66484 10.9061C5.48795 10.9538 5.3561 10.9863 5.2693 11.0009C5.08977 11.0214 4.96988 10.993 4.90956 10.9168C4.84931 10.8405 4.83276 10.7107 4.85924 10.5312C4.87315 10.4331 4.9043 10.292 4.95468 10.1078C5.00431 9.92297 5.05802 9.7315 5.11431 9.53341C5.1713 9.33526 5.22629 9.15179 5.27926 8.98484C5.33297 8.8179 5.37599 8.7026 5.40978 8.64032C5.44953 8.54357 5.49463 8.45413 5.54495 8.37399C5.59465 8.29379 5.66616 8.20503 5.75965 8.10766C5.79934 8.06588 5.89281 7.96649 6.03988 7.81018C6.18624 7.65311 6.80114 7.02774 7.02104 6.79783L7.75117 6.03524L8.56212 5.1899L10.6345 3.02466L12.5214 4.93874L10.4324 7.15226ZM13.816 3.58581C13.7166 3.68987 13.6272 3.78064 13.5483 3.85883C13.4694 3.93703 13.4006 4.0066 13.3423 4.06686C13.276 4.13643 13.2144 4.19738 13.1561 4.24903L11.2785 2.33569C11.3785 2.24025 11.4965 2.12565 11.6336 1.99115C11.7707 1.85668 11.8854 1.75061 11.9761 1.67242C12.0934 1.57708 12.2133 1.51013 12.3385 1.47109C12.4525 1.43529 12.5644 1.41805 12.6751 1.41876H12.7056C12.7665 1.42139 12.8268 1.42729 12.8851 1.43724C12.8838 1.4366 12.8811 1.43724 12.8798 1.4366C12.8811 1.4366 12.8838 1.4366 12.8851 1.43724C13.1376 1.48428 13.4019 1.62009 13.6265 1.83743C13.7511 1.95871 13.8524 2.09382 13.9259 2.23296C14.0346 2.43834 14.0863 2.65304 14.0763 2.8491C14.0763 2.87294 14.0783 2.89748 14.0783 2.92201C14.0783 3.03529 14.0571 3.14789 14.0154 3.26055C13.9737 3.37314 13.9067 3.48185 13.816 3.58581Z" fill="#0052D9"></path></svg></span></span>发布<span class="cdc-svg-icon-con cdc-header__create-btn-arrow"><span class="cdc-svg-icon" style="width:16px;height:16px"><svg width="16" height="16" viewBox="0 0 16 16" fill="currentcolor" xmlns="http://www.w3.org/2000/svg"><path d="M8.16377 4L9.57798 5.41421L14.5277 10.364L13.1135 11.7782L8.1638 6.829L3.21402 11.7782L1.7998 10.364L8.16377 4Z"></path></svg></span></span></span></div></div></div></div></div><div class="cdc-m-sticky-header is-hidden is-sticky"><div class="cdc-m-sticky-header__placeholder"></div><div class="cdc-m-sticky-header__main"><div class="cdc-m-sticky-header__con"><div class="cdc-m-sticky-header__trigger"></div><div class="cdc-m-header-article__menu"><div class="cdc-m-header-article__menu-mask"></div><div class="cdc-m-header-article__menu-side"><div class="cdc-m-header__sidebar"><div class="cdc-m-header__sidebar-top"><i class="cdc-m-header__sidebar-top__logo"></i><span class="cdc-m-header__sidebar-top__back"></span></div><div class="cdc-m-header__sidebar-menus"><a href="/developer" class="cdc-m-header__sidebar-menu link">首页</a><div class="tpm1-collapse"><div class="tpm1-collapse__panel"><header class="tpm1-collapse__panel-hd"><div class="tpm1-collapse__panel-title">学习</div></header></div><div class="tpm1-collapse__panel"><header class="tpm1-collapse__panel-hd"><div class="tpm1-collapse__panel-title">活动</div></header></div><div class="tpm1-collapse__panel"><header class="tpm1-collapse__panel-hd"><div class="tpm1-collapse__panel-title">专区</div></header></div><div class="tpm1-collapse__panel"><header class="tpm1-collapse__panel-hd"><div class="tpm1-collapse__panel-title">工具</div></header></div></div><a href="/tvp?from=20154&from_column=20154" class="cdc-m-header__sidebar-menu link">TVP</a><a class="cdc-m-header__sidebar-activity" href="/act?from=20061&from_column=20061" target="_blank">最新优惠活动<div class="cdc-badge"><div class="cdc-badge-inner"><div class="cdc-badge-text"></div></div></div></a></div><div class="cdc-m-header__sidebar-back"><a href="/?from=20060&from_column=20060" class="cdc-m-header__sidebar-back__link"><i></i><span>返回腾讯云官网</span></a></div></div></div></div><div class="cdc-m-sticky-header__author"><span class="cdc-avatar large circle" style="cursor:unset"><span class="cdc-avatar__inner" style="background-image:url(https://ask.qcloudimg.com/avatar/1444933/q9xecryc4m.png)"></span></span><div class="cdc-m-sticky-header__author-name">Erwin</div></div></div><div class="cdc-m-sticky-header__extra"><div class="cdc-m-sticky-header__extra-icon"><i class="extra-search"></i></div><div class="cdc-m-sticky-header__extra-icon"><i class="extra-share"></i></div><div class="cdc-m-sticky-header__extra-operate"><div class="cdc-m-sticky-header__extra-icon"><i class="extra-man"></i></div></div></div></div></div><div class="cdc-m-header-article"><div class="cdc-m-header-article__placeholder"></div><div class="cdc-m-header-article__content"><div class="cdc-m-header-article__main"><div class="cdc-m-header-article__con"><div class="cdc-m-header-article__trigger"></div><div class="cdc-m-header-article__menu"><div class="cdc-m-header-article__menu-mask"></div><div class="cdc-m-header-article__menu-side"><div class="cdc-m-header__sidebar"><div class="cdc-m-header__sidebar-top"><i class="cdc-m-header__sidebar-top__logo"></i><span class="cdc-m-header__sidebar-top__back"></span></div><div class="cdc-m-header__sidebar-menus"><a href="/developer" class="cdc-m-header__sidebar-menu link">首页</a><div class="tpm1-collapse"><div class="tpm1-collapse__panel"><header class="tpm1-collapse__panel-hd"><div class="tpm1-collapse__panel-title">学习</div></header></div><div class="tpm1-collapse__panel"><header class="tpm1-collapse__panel-hd"><div class="tpm1-collapse__panel-title">活动</div></header></div><div class="tpm1-collapse__panel"><header class="tpm1-collapse__panel-hd"><div class="tpm1-collapse__panel-title">专区</div></header></div><div class="tpm1-collapse__panel"><header class="tpm1-collapse__panel-hd"><div class="tpm1-collapse__panel-title">工具</div></header></div></div><a href="/tvp?from=20154&from_column=20154" class="cdc-m-header__sidebar-menu link">TVP</a><a class="cdc-m-header__sidebar-activity" href="/act?from=20061&from_column=20061" target="_blank">最新优惠活动<div class="cdc-badge"><div class="cdc-badge-inner"><div class="cdc-badge-text"></div></div></div></a></div><div class="cdc-m-header__sidebar-back"><a href="/?from=20060&from_column=20060" class="cdc-m-header__sidebar-back__link"><i></i><span>返回腾讯云官网</span></a></div></div></div></div></div><div class="cdc-m-header-article__title"><div class="cdc-m-header-article__title-logo"></div></div><div class="cdc-m-header-article__extra"><div class="cdc-m-header-article__extra-icon"><i class="extra-search"></i></div><div class="cdc-m-header-article__extra-operate"><div class="cdc-m-header-article__extra-icon"><i class="extra-man"></i></div></div></div></div></div></div><div class="cdc-global__main"><div class="cdc-article__body"><div class="cdc-layout"><div class="cdc-layout__main"><div class="cdc-crumb mod-crumb"><div class="cdc-crumb__inner"><a class="cdc-crumb__item" href="/developer">社区首页</a><span class="cdc-crumb__split"> ></span><a class="cdc-crumb__item" href="/developer/column">专栏</a><span class="cdc-crumb__split"> ></span><span class="cdc-crumb__item current">理解Future及FutureTask的实现</span></div></div><div class="mod-article-content"><div class="mod-header2"><div class="mod-header2__top"><div class="mod-header2__title"><h1 class="title-text">理解Future及FutureTask的实现</h1></div></div><div class="mod-article-source header"><div class="mod-article-source__main"><div class="mod-article-source__avatar"><img src="https://ask.qcloudimg.com/avatar/1444933/q9xecryc4m.png" alt="作者头像"/></div><div class="mod-article-source__detail"><div class="mod-article-source__name"><span>Erwin</span></div></div><button class="cdc-btn mod-article-source__operate cdc-btn--primary"><span><i></i>关注</span></button></div></div><div class="mod-header2__bottom"><div class="mod-header2__detail"><div class="mod-header2__date"><span class="date-text">发布<!-- -->于 <!-- -->2020-08-17 10:41:44</span></div><div class="mod-header2__infos"><div class="cdc-icon__list"><span class="cdc-svg-icon-con"><span class="cdc-svg-icon" style="width:16px;height:16px"><svg width="16" height="16" viewBox="0 0 16 16" fill="currentcolor" xmlns="http://www.w3.org/2000/svg"><g id="icon-view" transform="translate(0.000000, 3.000000)" fill="currentcolor" fill-rule="nonzero"><path d="M15.885,4.68036 C14.9951,3.57569 11.7987,-0.004272 7.99883,-0.004272 C4.19895,-0.004272 1.02302,3.57569 0.112682,4.68036 C0.040058,4.77107 0.000488281,4.88381 0.000488281,5 C0.000488281,5.1162 0.040058,5.22894 0.112682,5.31964 C1.00767,6.42432 4.20407,10.0043 7.99883,10.0043 C11.7936,10.0043 14.9951,6.42432 15.885,5.31964 C15.9576,5.22894 15.9972,5.1162 15.9972,5 C15.9972,4.88381 15.9576,4.77107 15.885,4.68036 Z M7.99883,8.97632 C4.93029,8.97632 2.25555,6.25043 1.17644,4.99745 C2.25555,3.74446 4.95586,1.01857 7.99883,1.01857 C11.0418,1.01857 13.7421,3.74446 14.8314,4.99745 C13.7421,6.25043 11.0418,8.97632 7.99883,8.97632 Z" id="形状"></path><path d="M7.97304,2.55286 C7.49865,2.55286 7.03491,2.69353 6.64046,2.95709 C6.24602,3.22065 5.93859,3.59525 5.75704,4.03354 C5.5755,4.47182 5.528,4.95409 5.62055,5.41937 C5.7131,5.88465 5.94154,6.31203 6.27699,6.64748 C6.61244,6.98293 7.03982,7.21137 7.5051,7.30392 C7.97038,7.39647 8.45265,7.34897 8.89093,7.16743 C9.32922,6.98588 9.70382,6.67845 9.96738,6.28401 C10.2309,5.88956 10.3716,5.42582 10.3716,4.95143 C10.3716,4.31529 10.1189,3.7052 9.66909,3.25538 C9.21927,2.80556 8.60918,2.55286 7.97304,2.55286 Z M7.97304,6.32716 C7.70095,6.32716 7.43496,6.24647 7.20872,6.09531 C6.98249,5.94414 6.80616,5.72928 6.70203,5.4779 C6.59791,5.22652 6.57066,4.94991 6.62374,4.68304 C6.67683,4.41617 6.80785,4.17104 7.00025,3.97864 C7.19265,3.78625 7.43778,3.65522 7.70465,3.60214 C7.97151,3.54905 8.24813,3.5763 8.49951,3.68042 C8.75089,3.78455 8.96575,3.96088 9.11692,4.18712 C9.26808,4.41335 9.34877,4.67934 9.34877,4.95143 C9.35012,5.13295 9.31553,5.31295 9.247,5.48104 C9.17846,5.64913 9.07734,5.802 8.94946,5.93084 C8.82158,6.05967 8.66946,6.16192 8.50188,6.2317 C8.3343,6.30147 8.15457,6.33739 7.97304,6.33739 L7.97304,6.32716 Z" id="形状"></path></g></svg></span><span class="cdc-svg-icon-text">1.3K</span></span><span class="cdc-svg-icon-con is-comment"><span class="cdc-svg-icon" style="width:16px;height:16px"><svg width="16" height="16" viewBox="0 0 16 16" fill="currentcolor" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M8 13.414L5.58594 11H2V3H14V11H10.4141L8 13.414ZM5.17175 12L8 14.8282L10.8282 12H15V2H1V12H5.17175ZM4 6C3.44775 6 3 6.44769 3 7C3 7.55231 3.44775 8 4 8C4.55225 8 5 7.55231 5 7C5 6.44769 4.55225 6 4 6ZM7 7C7 6.44769 7.44775 6 8 6C8.55225 6 9 6.44769 9 7C9 7.55231 8.55225 8 8 8C7.44775 8 7 7.55231 7 7ZM12 6C11.4478 6 11 6.44769 11 7C11 7.55231 11.4478 8 12 8C12.5522 8 13 7.55231 13 7C13 6.44769 12.5522 6 12 6Z"></path></svg></span><span class="cdc-svg-icon-text">0</span></span></div></div><div class="mod-header2__date is-mobile"><span class="date-text">发布<!-- -->于 <!-- -->2020-08-17 10:41:44</span></div></div><div class="mod-header2__operates"><div class="mod-header2__operate"><span class="cdc-svg-icon-con is-operate"><span class="cdc-svg-icon" style="width:16px;height:16px"><svg width="16" height="16" viewBox="0 0 16 16" fill="currentcolor" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M9.21101 2.54545C8.80733 1.81818 7.79814 1.81818 7.39446 2.54545L1.94481 12.3636C1.54113 13.0909 2.04573 14 2.85308 14H13.7524C14.5597 14 15.0643 13.0909 14.6607 12.3636L9.21101 2.54545ZM2.85308 12.9091L8.30273 3.09091L13.7524 12.9091H2.85308ZM8.00037 6H9.00037V10H8.00037V6ZM8.00037 11H9.00037V12H8.00037V11Z" fill="currentcolor"></path></svg></span><span class="cdc-svg-icon-text">举报</span></span></div></div></div><div class="mod-header2__special"><div class="cdc-special-guide"><span><i class="cdc-special-guide-icon"></i>文章被收录于专栏:</span><a class="cdc-special-guide-name">啸天"s blog</a></div></div></div><div class="mod-content"><div class="mod-content__markdown"><div><div class="rno-markdown new-version rno-"><h3 id="24rhp" name="%E6%A6%82%E8%A6%81">概要</h3><p>Future是一种异步计算的模式,本文带你理解一下什么是Future,以及基本的FutureTask的实现原理。</p><h3 id="alp3n" name="%E4%BD%9C%E7%94%A8">作用</h3><p>如果在一个方法中要执行另一个操作(任务),但是这个操作会耗时很久,而且你后面还需要用到这个操作的返回结果或者必须等到这个操作结束你才能走下去,你会怎样做?可能大家都会想到异步去执行,即新建一个线程去做这个事情,但是这样的话,你后面的操作就要放到这个异步线程那里,你的方法就变成异步的了,对你原来的返回造成了影响。 这时候,Future就发挥作用了,有些地方说它是一种模式,其实,它就是对一个异步操作的封装,它会返回一个"凭证"给你,你可以用这个"凭证"在需要的时候获取到这个异步操作的结果,一般来说这个"凭证"就是future。</p><h3 id="2ulip" name="%E5%8E%9F%E7%90%86">原理</h3><p>FutureTask就是Future的基本实现,下面我们就从代码分析一下实现的原理。 <a style="color:#0052D9" class="" href="/developer/tools/blog-entry?target=https%3A%2F%2Fxtboke.cn%2Ftag-%25E6%25BA%2590%25E7%25A0%2581.html&objectId=1680378&objectType=1" target="_blank" rel="nofollow noopener">源码</a>基本JDK1.8。</p><p>Future接口</p><p>我们先看看Future的定义,即你拿到这个"凭证"之后你能干点什么。</p><div class="rno-markdown-code"><div class="rno-markdown-code-toolbar"><div class="rno-markdown-code-toolbar-info"><div class="rno-markdown-code-toolbar-item is-type"><span class="is-m-hidden">代码语言:</span>javascript</div></div><div class="rno-markdown-code-toolbar-opt"><div class="rno-markdown-code-toolbar-copy"><i class="icon-copy"></i><span class="is-m-hidden">复制</span></div></div></div><div class="developer-code-block"><pre class="prism-token token line-numbers language-javascript"><code class="language-javascript" style="margin-left:0">public interface Future<V> { //取消这次任务 boolean cancel(boolean mayInterruptIfRunning); //看看是否取消了 boolean isCancelled(); //看看是否完成了 boolean isDone(); //获取结果 V get() throws InterruptedException, ExecutionException; //时间内获取结果,超时则抛异常 V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; }</code></pre></div></div><h4 id="bvt0b" name="%E4%BD%BF%E7%94%A8">使用</h4><p>如果没用过的,这里简单演示一下Future怎么使用,大家有个感性认识。</p><div class="rno-markdown-code"><div class="rno-markdown-code-toolbar"><div class="rno-markdown-code-toolbar-info"><div class="rno-markdown-code-toolbar-item is-type"><span class="is-m-hidden">代码语言:</span>javascript</div></div><div class="rno-markdown-code-toolbar-opt"><div class="rno-markdown-code-toolbar-copy"><i class="icon-copy"></i><span class="is-m-hidden">复制</span></div></div></div><div class="developer-code-block"><pre class="prism-token token line-numbers language-javascript"><code class="language-javascript" style="margin-left:0">private static ExecutorService threadPool = Executors.newCachedThreadPool(); public static void main(String[] args) throws Exception { //通过线程池提交任务,并返回一个future Future<String> future = threadPool.submit(new AsyncTask()); //通过future获取结果。get之前一直阻塞直到有结果返回。 String result = future.get(); System.out.println(result); } public class AsyncTask implements Callable<String> { @Override public String call() throws Exception { TimeUnit.SECONDS.sleep(5); return "ok"; } }</code></pre></div></div><h4 id="ed8lt" name="%E7%BB%A7%E6%89%BF%E5%85%B3%E7%B3%BB">继承关系</h4><figure class=""><div class="rno-markdown-img-url" style="text-align:center"><div class="rno-markdown-img-url-inner" style="width:100%"><div style="width:100%"><img src="https://ask.qcloudimg.com/http-save/yehe-1444933/6ske3hyobj.png" style="width:100%"/></div></div></div></figure><p>FutureTask是一个RunnableFuture,这个很好理解,就是Runnable+Future了。</p><h4 id="b7a32" name="%E6%8F%90%E4%BA%A4%E4%BB%BB%E5%8A%A1">提交任务</h4><p>从任务的提交入手分析源码。 AbstractExecutorService的submit方法。</p><div class="rno-markdown-code"><div class="rno-markdown-code-toolbar"><div class="rno-markdown-code-toolbar-info"><div class="rno-markdown-code-toolbar-item is-type"><span class="is-m-hidden">代码语言:</span>javascript</div></div><div class="rno-markdown-code-toolbar-opt"><div class="rno-markdown-code-toolbar-copy"><i class="icon-copy"></i><span class="is-m-hidden">复制</span></div></div></div><div class="developer-code-block"><pre class="prism-token token line-numbers language-javascript"><code class="language-javascript" style="margin-left:0">public <T> Future<T> submit(Callable<T> task) { if (task == null) throw new NullPointerException(); //这里封装了一下callable变成一个RunnableFuture RunnableFuture<T> ftask = newTaskFor(task); //注意线程池执行的是RunnableFuture,因为这个Future继承Runnable,所以它是可执行的。 execute(ftask); //返回future return ftask; }</code></pre></div></div><p>submit方法也是支持Runnable的。ExecutorService内部会把Runnable转成Callable,只不过Runnable的返回值为null。</p><h4 id="61bp8" name="FutureTask%E7%9A%84%E5%B1%9E%E6%80%A7/%E7%8A%B6%E6%80%81">FutureTask的属性/状态</h4><p>先看下FutureTask的一些内部属性,才好了解它是怎么运行的。</p><div class="rno-markdown-code"><div class="rno-markdown-code-toolbar"><div class="rno-markdown-code-toolbar-info"><div class="rno-markdown-code-toolbar-item is-type"><span class="is-m-hidden">代码语言:</span>javascript</div></div><div class="rno-markdown-code-toolbar-opt"><div class="rno-markdown-code-toolbar-copy"><i class="icon-copy"></i><span class="is-m-hidden">复制</span></div></div></div><div class="developer-code-block"><pre class="prism-token token line-numbers language-javascript"><code class="language-javascript" style="margin-left:0">//重要属性"状态"state定义为volatile,为了在高并发下能够获取到最新的值 private volatile int state; //为state定义了7个状态,看名字都挺好了解的。 private static final int NEW = 0; private static final int COMPLETING = 1; //正常结束 private static final int NORMAL = 2; private static final int EXCEPTIONAL = 3; private static final int CANCELLED = 4; private static final int INTERRUPTING = 5; private static final int INTERRUPTED = 6; //状态之间的转换 * Possible state transitions: * NEW -> COMPLETING -> NORMAL * NEW -> COMPLETING -> EXCEPTIONAL * NEW -> CANCELLED * NEW -> INTERRUPTING -> INTERRUPTED */ //用户提交的真正任务 private Callable<V> callable; //返回结果 private Object outcome; // non-volatile, protected by state reads/writes //记录跑任务的那个线程,只有一个在运行。取消时可以中断这个线程的行为。 private volatile Thread runner; /** Treiber stack of waiting threads */ //这个属性比较重要,后面讲的比较多。记录WaitNode链表的头部,volatile。WaitNode链表是等待结果的线程集合,即这个任务还没跑完时,但同时有很多持有这个future的线程调用了get方法获取结果。 private volatile WaitNode waiters;</code></pre></div></div><h4 id="c2s51" name="run%E6%96%B9%E6%B3%95">run方法</h4><p>当这个RunnableFuture提交到线程池后,它做了什么。</p><div class="rno-markdown-code"><div class="rno-markdown-code-toolbar"><div class="rno-markdown-code-toolbar-info"><div class="rno-markdown-code-toolbar-item is-type"><span class="is-m-hidden">代码语言:</span>javascript</div></div><div class="rno-markdown-code-toolbar-opt"><div class="rno-markdown-code-toolbar-copy"><i class="icon-copy"></i><span class="is-m-hidden">复制</span></div></div></div><div class="developer-code-block"><pre class="prism-token token line-numbers language-javascript"><code class="language-javascript" style="margin-left:0">public void run() { //为了防止future重复运行,需要判断是NEW状态。 //同时记录runner属性 //这里UNSAFE的CAS操作在JUC里用的比较多,不展开了(我的原则是,不是这个话题的内容不过多展开,保持专注和精简。) if (state != NEW || !UNSAFE.compareAndSwapObject(this, runnerOffset, null, Thread.currentThread())) return; try { Callable<V> c = callable; if (c != null && state == NEW) { V result; boolean ran; try { //执行用户的callable result = c.call(); ran = true; } catch (Throwable ex) { result = null; ran = false; //如果callable运行异常了,这里会把这个异常吃掉,然后调用setException方法 setException(ex); } if (ran) //正常结束就是设置结果 set(result); } } finally { // runner must be non-null until state is settled to // prevent concurrent calls to run() runner = null; // state must be re-read after nulling runner to prevent // leaked interrupts int s = state; if (s >= INTERRUPTING) handlePossibleCancellationInterrupt(s); } }</code></pre></div></div><p>值得注意的是,如果原来的callable任务运行异常了,那么在run方法中会直接catch掉,然后在get的时候才抛出来。这么也是为了做错误隔离,为了callable的异常不会影响到future的运行。</p><h5 id="b6i9c" name="setException%E6%96%B9%E6%B3%95">setException方法</h5><div class="rno-markdown-code"><div class="rno-markdown-code-toolbar"><div class="rno-markdown-code-toolbar-info"><div class="rno-markdown-code-toolbar-item is-type"><span class="is-m-hidden">代码语言:</span>javascript</div></div><div class="rno-markdown-code-toolbar-opt"><div class="rno-markdown-code-toolbar-copy"><i class="icon-copy"></i><span class="is-m-hidden">复制</span></div></div></div><div class="developer-code-block"><pre class="prism-token token line-numbers language-javascript"><code class="language-javascript" style="margin-left:0">protected void setException(Throwable t) { if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) { //把结果设为异常 outcome = t; //更新状态为EXCEPTIONAL UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state //finishCompletion作为一个结束动作 finishCompletion(); } }</code></pre></div></div><h5 id="85gvg" name="set%E6%96%B9%E6%B3%95">set方法</h5><div class="rno-markdown-code"><div class="rno-markdown-code-toolbar"><div class="rno-markdown-code-toolbar-info"><div class="rno-markdown-code-toolbar-item is-type"><span class="is-m-hidden">代码语言:</span>javascript</div></div><div class="rno-markdown-code-toolbar-opt"><div class="rno-markdown-code-toolbar-copy"><i class="icon-copy"></i><span class="is-m-hidden">复制</span></div></div></div><div class="developer-code-block"><pre class="prism-token token line-numbers language-javascript"><code class="language-javascript" style="margin-left:0">protected void set(V v) { if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) { //设置结果 outcome = v; //更新状态为NORMAL UNSAFE.putOrderedInt(this, stateOffset, NORMAL); //同样调用了finishCompletion方法 finishCompletion(); } }</code></pre></div></div><p>setException方法和set方法都是protected,不能随意调用,不过子类可以改变它的行为。</p><h5 id="cb1ci" name="COMPLETING%E7%8A%B6%E6%80%81%EF%BC%9F">COMPLETING状态?</h5><p>在上面说到的7个状态中有一个COMPLETING的状态,它表示新建NEW和正常结束NORMAL或异常结束EXCEPTIONAL中间的这么一个状态,在set和setException用到了,会先把NEW状态更新为COMPLETING,再把COMPLETING更新为对应的结果状态。 刚开始我认为这个状态是没必要的。因为这个FutureTask只会有一个线程在运行它,不存在竞争,而且看代码也知道,作者没对竞争失败做处理,那么set和setException的CAS操作是肯定会成功的,所以我觉得把COMPLETING变成NEW也是可以的。但是细想如果直接把</p><div class="rno-markdown-code"><div class="rno-markdown-code-toolbar"><div class="rno-markdown-code-toolbar-info"><div class="rno-markdown-code-toolbar-item is-type"><span class="is-m-hidden">代码语言:</span>javascript</div></div><div class="rno-markdown-code-toolbar-opt"><div class="rno-markdown-code-toolbar-copy"><i class="icon-copy"></i><span class="is-m-hidden">复制</span></div></div></div><div class="developer-code-block"><pre class="prism-token token line-numbers language-javascript"><code class="language-javascript" style="margin-left:0">UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)</code></pre></div></div><p>变成</p><div class="rno-markdown-code"><div class="rno-markdown-code-toolbar"><div class="rno-markdown-code-toolbar-info"><div class="rno-markdown-code-toolbar-item is-type"><span class="is-m-hidden">代码语言:</span>javascript</div></div><div class="rno-markdown-code-toolbar-opt"><div class="rno-markdown-code-toolbar-copy"><i class="icon-copy"></i><span class="is-m-hidden">复制</span></div></div></div><div class="developer-code-block"><pre class="prism-token token line-numbers language-javascript"><code class="language-javascript" style="margin-left:0">UNSAFE.compareAndSwapInt(this, stateOffset, NEW, NORMAL)</code></pre></div></div><p>但是后面还有一步赋值操作。</p><div class="rno-markdown-code"><div class="rno-markdown-code-toolbar"><div class="rno-markdown-code-toolbar-info"><div class="rno-markdown-code-toolbar-item is-type"><span class="is-m-hidden">代码语言:</span>javascript</div></div><div class="rno-markdown-code-toolbar-opt"><div class="rno-markdown-code-toolbar-copy"><i class="icon-copy"></i><span class="is-m-hidden">复制</span></div></div></div><div class="developer-code-block"><pre class="prism-token token line-numbers language-javascript"><code class="language-javascript" style="margin-left:0">outcome = v</code></pre></div></div><p>并发下,这时如果有其他线程在CAS后想获取结果,就返回null了。</p><p>finishCompletion方法</p><div class="rno-markdown-code"><div class="rno-markdown-code-toolbar"><div class="rno-markdown-code-toolbar-info"><div class="rno-markdown-code-toolbar-item is-type"><span class="is-m-hidden">代码语言:</span>javascript</div></div><div class="rno-markdown-code-toolbar-opt"><div class="rno-markdown-code-toolbar-copy"><i class="icon-copy"></i><span class="is-m-hidden">复制</span></div></div></div><div class="developer-code-block"><pre class="prism-token token line-numbers language-javascript"><code class="language-javascript" style="margin-left:0">//如果这个future正常结束,异常结束,被取消了,都会调用这个方法。 private void finishCompletion() { // assert state > COMPLETING; //这里会不停的拿头部节点做遍历,直到头部节点为null。这是为了防止在并发下有新的节点新插入进来。 for (WaitNode q; (q = waiters) != null;) { //CAS把WaitNode链表的头部设为null。 if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) { for (;;) { Thread t = q.thread; if (t != null) { q.thread = null; //唤醒WaitNode的线程,唤醒的线程继续在awaitDone方法里做循环。 LockSupport.unpark(t); } WaitNode next = q.next; //直到next为null,完成链表的遍历 if (next == null) break; q.next = null; // unlink to help gc q = next; } break; } } //这个done方法是预留方法,子类可以继承它来做点别的。 done(); callable = null; // to reduce footprint }</code></pre></div></div><h4 id="5dnh2" name="get%E6%96%B9%E6%B3%95">get方法</h4><p>get方法是重点。 因为作者设计FutureTask是支持高并发的,而且用了Lock-Free无锁算法,所以阅读起来会比较费劲。</p><div class="rno-markdown-code"><div class="rno-markdown-code-toolbar"><div class="rno-markdown-code-toolbar-info"><div class="rno-markdown-code-toolbar-item is-type"><span class="is-m-hidden">代码语言:</span>javascript</div></div><div class="rno-markdown-code-toolbar-opt"><div class="rno-markdown-code-toolbar-copy"><i class="icon-copy"></i><span class="is-m-hidden">复制</span></div></div></div><div class="developer-code-block"><pre class="prism-token token line-numbers language-javascript"><code class="language-javascript" style="margin-left:0">public V get() throws InterruptedException, ExecutionException { int s = state; if (s <= COMPLETING) s = awaitDone(false, 0L); return report(s); }</code></pre></div></div><h5 id="358l7" name="WaitNode%E9%93%BE%E8%A1%A8">WaitNode链表</h5><p>继续看下去之前,先看看WaitNode的定义。 很简单,只有一个Thread和next指针。Thread就是指当前需要获取future结果的那个线程。WaitNode通过next指针形成一条链表。</p><div class="rno-markdown-code"><div class="rno-markdown-code-toolbar"><div class="rno-markdown-code-toolbar-info"><div class="rno-markdown-code-toolbar-item is-type"><span class="is-m-hidden">代码语言:</span>javascript</div></div><div class="rno-markdown-code-toolbar-opt"><div class="rno-markdown-code-toolbar-copy"><i class="icon-copy"></i><span class="is-m-hidden">复制</span></div></div></div><div class="developer-code-block"><pre class="prism-token token line-numbers language-javascript"><code class="language-javascript" style="margin-left:0">static final class WaitNode { volatile Thread thread; volatile WaitNode next; WaitNode() { thread = Thread.currentThread(); } }</code></pre></div></div><p>这是在Lock-Free中常见的数据结构,看上去是不是有点像AQS呢?</p><div class="rno-markdown-code"><div class="rno-markdown-code-toolbar"><div class="rno-markdown-code-toolbar-info"><div class="rno-markdown-code-toolbar-item is-type"><span class="is-m-hidden">代码语言:</span>javascript</div></div><div class="rno-markdown-code-toolbar-opt"><div class="rno-markdown-code-toolbar-copy"><i class="icon-copy"></i><span class="is-m-hidden">复制</span></div></div></div><div class="developer-code-block"><pre class="prism-token token line-numbers language-javascript"><code class="language-javascript" style="margin-left:0">/* * Revision notes: This differs from previous versions of this * class that relied on AbstractQueuedSynchronizer, mainly to * avoid surprising users about retaining interrupt status during * cancellation races. Sync control in the current design relies * on a "state" field updated via CAS to track completion, along * with a simple Treiber stack to hold waiting threads. * * Style note: As usual, we bypass overhead of using * AtomicXFieldUpdaters and instead directly use Unsafe intrinsics. */</code></pre></div></div><p>实际上,官方也说了,之前版本的实现是用了AQS的,原因是...(这个原因我不是很懂是啥意思),现在改为Treiber stack算法了。</p><h5 id="eahh" name="awaitDone%E6%96%B9%E6%B3%95">awaitDone方法</h5><div class="rno-markdown-code"><div class="rno-markdown-code-toolbar"><div class="rno-markdown-code-toolbar-info"><div class="rno-markdown-code-toolbar-item is-type"><span class="is-m-hidden">代码语言:</span>javascript</div></div><div class="rno-markdown-code-toolbar-opt"><div class="rno-markdown-code-toolbar-copy"><i class="icon-copy"></i><span class="is-m-hidden">复制</span></div></div></div><div class="developer-code-block"><pre class="prism-token token line-numbers language-javascript"><code class="language-javascript" style="margin-left:0">private int awaitDone(boolean timed, long nanos) throws InterruptedException { final long deadline = timed ? System.nanoTime() + nanos : 0L; WaitNode q = null; boolean queued = false; //死循环直到s > COMPLETING或者超时,当然这个不是真的死循环,大部分情况下线程是会挂起的。 for (;;) { //如果线程是被中断了,则从链表移除当前节点,然后抛异常 if (Thread.interrupted()) { removeWaiter(q); throw new InterruptedException(); } int s = state; //从上面7个状态看出,当s > COMPLETING都是结束的状态,要不正常结束,异常,取消等。可见合理的状态值设计带来的方便。 if (s > COMPLETING) { if (q != null) q.thread = null; return s; } //这里就是为了防止上面我说的,结果赋值时并发下其他线程获取不到值的情况,所以让这个线程yield一下,再做一次循环,说不定下次就是s > COMPLETING呢。 else if (s == COMPLETING) // cannot time out yet Thread.yield(); else if (q == null) //新建一个WaitNode,准备进链表 q = new WaitNode(); else if (!queued) //CAS把WaitNode节点插入到链表的头部,如果失败则下次继续插入 queued = UNSAFE.compareAndSwapObject(this, waitersOffset, q.next = waiters, q); //如果get方法设置了超时时间,则会进入这个分支,如果超时了,也会返回state。还没超时则挂起,挂起的时间为时间差。 else if (timed) { nanos = deadline - System.nanoTime(); if (nanos <= 0L) { //超时需要从链表移除当前节点 removeWaiter(q); return state; } LockSupport.parkNanos(this, nanos); } //注意这里,是最后的步骤,即当s < COMPLETING,已经插入链表了,不是超时的情况 else LockSupport.park(this); } }</code></pre></div></div><p>awaitDone方法返回的是state状态的值。 要注意if else执行的顺序,先是判断中断状态,其次判断state的完成状态,再是新建节点,然后插入,最后才是挂起。用for循环去尝试当CAS失败的情况。</p><p>插入节点的只有这个方法,所以我们可以知道,链表的结构如下:</p><figure class=""><div class="rno-markdown-img-url" style="text-align:center"><div class="rno-markdown-img-url-inner" style="width:100%"><div style="width:100%"><img src="https://ask.qcloudimg.com/http-save/yehe-1444933/9xbcz2r4ih.png" style="width:100%"/></div></div></div></figure><p>removeWaiter方法的作用是当中断或超时时移除当前的WaitNode。这个方法有点不好理解。</p><div class="rno-markdown-code"><div class="rno-markdown-code-toolbar"><div class="rno-markdown-code-toolbar-info"><div class="rno-markdown-code-toolbar-item is-type"><span class="is-m-hidden">代码语言:</span>javascript</div></div><div class="rno-markdown-code-toolbar-opt"><div class="rno-markdown-code-toolbar-copy"><i class="icon-copy"></i><span class="is-m-hidden">复制</span></div></div></div><div class="developer-code-block"><pre class="prism-token token line-numbers language-javascript"><code class="language-javascript" style="margin-left:0">private void removeWaiter(WaitNode node) { if (node != null) { node.thread = null; retry: for (;;) { // restart on removeWaiter race for (WaitNode pred = null, q = waiters, s; q != null; q = s) { s = q.next; if (q.thread != null) pred = q; else if (pred != null) { pred.next = s; if (pred.thread == null) // check for race continue retry; } else if (!UNSAFE.compareAndSwapObject(this, waitersOffset, q, s)) continue retry; } break; } } }</code></pre></div></div><p>我们画个图,分情况来理解一下</p><figure class=""><div class="rno-markdown-img-url" style="text-align:center"><div class="rno-markdown-img-url-inner" style="width:100%"><div style="width:100%"><img src="https://ask.qcloudimg.com/http-save/yehe-1444933/095h7lczvv.png" style="width:100%"/></div></div></div></figure><ol class="ol-level-0"><li>如果q.thread != null 因为进来时已经直接把node.thread = null,说明q已经不是当前的node,q是其他线程插入进来的node,这时需要把s,q,pred继续往左移动。</li><li>如果q.thread == null && pred != null 这时可以把pred的next指向s了,即删除了q。但是如果pred.thread == null,说明pred的线程也把它自己的节点删除了(删除节点的情况除了removeWaiter,还有正常获取结果后也会),所以pred已经没用了,需要重新来找到新的pred。</li><li>如果q.thread == null && pred == null 说明前面的节点都被删除了,已经没用了,把s直接置为头部。</li></ol><h5 id="c6ql7" name="report%E6%96%B9%E6%B3%95"><a style="color:#0052D9" class="" href="/developer/tools/blog-entry?target=https%3A%2F%2Fxtboke.cn%2Ftag-repo.html&objectId=1680378&objectType=1" target="_blank" rel="nofollow noopener">repo</a>rt方法</h5><p>比较简单了</p><div class="rno-markdown-code"><div class="rno-markdown-code-toolbar"><div class="rno-markdown-code-toolbar-info"><div class="rno-markdown-code-toolbar-item is-type"><span class="is-m-hidden">代码语言:</span>javascript</div></div><div class="rno-markdown-code-toolbar-opt"><div class="rno-markdown-code-toolbar-copy"><i class="icon-copy"></i><span class="is-m-hidden">复制</span></div></div></div><div class="developer-code-block"><pre class="prism-token token line-numbers language-javascript"><code class="language-javascript" style="margin-left:0">private V report(int s) throws ExecutionException { Object x = outcome; if (s == NORMAL) //task正常执行就返回结果 return (V)x; if (s >= CANCELLED) //取消则抛异常 throw new CancellationException(); //否则抛出task运行的异常 throw new ExecutionException((Throwable)x); }</code></pre></div></div><h4 id="6q5g0" name="cancel%E6%96%B9%E6%B3%95">cancel方法</h4><div class="rno-markdown-code"><div class="rno-markdown-code-toolbar"><div class="rno-markdown-code-toolbar-info"><div class="rno-markdown-code-toolbar-item is-type"><span class="is-m-hidden">代码语言:</span>javascript</div></div><div class="rno-markdown-code-toolbar-opt"><div class="rno-markdown-code-toolbar-copy"><i class="icon-copy"></i><span class="is-m-hidden">复制</span></div></div></div><div class="developer-code-block"><pre class="prism-token token line-numbers language-javascript"><code class="language-javascript" style="margin-left:0">//mayInterruptIfRunning参数,取消的同时可以中断runner线程的运行。 public boolean cancel(boolean mayInterruptIfRunning) { //状态更新为INTERRUPTING或CANCELLED if (!(state == NEW && UNSAFE.compareAndSwapInt(this, stateOffset, NEW, mayInterruptIfRunning ? INTERRUPTING : CANCELLED))) return false; try { // in case call to interrupt throws exception //中断 if (mayInterruptIfRunning) { try { Thread t = runner; if (t != null) //调用线程的interrupt方法来中断线程 t.interrupt(); } finally { // final state UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED); } } } finally { //取消也要把watiers清空掉 finishCompletion(); } return true; }</code></pre></div></div><h3 id="3jd90" name="%E7%BC%BA%E7%82%B9">缺点</h3><p>FutureTask有明显的下面两个缺点:</p><ol class="ol-level-0"><li>重复提交 并发会有重复提交的可能,虽然在内部有对状态NEW的判断,但那只是针对那个FutureTask实例的,我们看到,在submit方法中每次提交任务都会new 一个 FutureTask出来的。 不过现在已经有一个解决方案<a style="color:#0052D9" class="" href="/developer/tools/blog-entry?target=http%3A%2F%2Fjcip.net%2Flistings%2FMemoizer.java&objectId=1680378&objectType=1" target="_blank" rel="nofollow noopener">Memoizer</a> 其实很简单,就是用一个key来记录这次的Future,然后放在一个Map里,下次用到时再从Map里取出来。</li><li>批量任务 Future每次只能提交一个任务,而且获取结果之前会一直阻塞,这点也是很不友好的。</li></ol><p>综上,FutureTask只是提供了一个基本的功能实现,远远不能满足要求高的我们,guava的ListenableFuture和JDK1.8的CompletableFuture都是对Future的增强,前者提供监听器处理结果,后者更加强大,提供链式调用,同步、异步结果返回不同的组合方式来帮助你处理复杂的业务场景。</p><h3 id="b3cih" name="%E6%80%BB%E7%BB%93">总结</h3><p>源码部分已经介绍的7788了。因为采用了无锁算法,所以实现起来看上去代码比较复杂,看代码时要意识到这个,多想想在高并发下链表会出现怎样的情况,我没有把所有可能出现的情况都罗列出来,所以要靠读者自己多思考。</p><p>总的来说,Future通过循环判断state状态,挂起、唤醒线程的操作,来实现异步阻塞,通过一个WaitNode链表来处理并发的情况。</p></div></div></div><div class="mod-content__source"><div class="mod-content__source-inner"><div class="mod-content__source-title">本文参与 <a href="/developer/support-plan" target="_blank">腾讯云自媒体同步曝光计划</a>,分享自作者个人站点/博客。</div><div class="mod-content__source-desc"> 原始发表:2020-08-14,<!-- -->如有侵权请联系 <a href="mailto:cloudcommunity@tencent.com">cloudcommunity@tencent.com</a> 删除</div></div><div class="mod-content__source-btn"><button class="cdc-btn cdc-btn--hole">前往查看</button></div></div><div class="mod-statement-m"><div class="cdc-tag__list mod-content__tags" track-click=""><div class="cdc-tag" track-click="" track-exposure=""><a class="cdc-tag__inner" href="/developer/tag/10663" target="_blank">编程算法</a></div><div class="cdc-tag" track-click="" track-exposure=""><a class="cdc-tag__inner" href="/developer/tag/10802" target="_blank">数据分析</a></div><div class="cdc-tag" track-click="" track-exposure=""><a class="cdc-tag__inner" href="/developer/tag/10620" target="_blank">http</a></div><div class="cdc-tag" track-click="" track-exposure=""><a class="cdc-tag__inner" href="/developer/tag/10200" target="_blank">node.js</a></div></div><div class="mod-content__statement"><p>本文分享自 <span>作者个人站点/博客</span> <span style="color:#0052d9;cursor:pointer">前往查看</span></p><p>如有侵权,请联系 <a href="mailto:cloudcommunity@tencent.com">cloudcommunity@tencent.com</a> 删除。</p><p class="mod-content__statement-tip">本文参与 <a href="/developer/support-plan" target="_blank">腾讯云自媒体同步曝光计划</a> ,欢迎热爱写作的你一起参与!</p></div></div><div class="cdc-tag__list mod-content__tags" track-click=""><div class="cdc-tag" track-click="" track-exposure=""><a class="cdc-tag__inner" href="/developer/tag/10663" target="_blank">编程算法</a></div><div class="cdc-tag" track-click="" track-exposure=""><a class="cdc-tag__inner" href="/developer/tag/10802" target="_blank">数据分析</a></div><div class="cdc-tag" track-click="" track-exposure=""><a class="cdc-tag__inner" href="/developer/tag/10620" target="_blank">http</a></div><div class="cdc-tag" track-click="" track-exposure=""><a class="cdc-tag__inner" href="/developer/tag/10200" target="_blank">node.js</a></div></div></div></div><div class="mod-article-content is-pill-hidden"><div class="mod-comment"><div class="mod-relevant__title">评论</div><div class="cdc-comment-response"><div class="cdc-comment-response-single-edit not-logged"><div class="cdc-comment-response-single-edit__inner"><span class="cdc-avatar cdc-comment-response-single-edit__avatar cdc-comment__avatar circle"><span class="cdc-avatar__inner" style="background-image:url(https://qcloudimg.tencent-cloud.cn/raw/2eca91c9c29816ff056d22815949d83c.png)" target="_blank"></span></span><div class="cdc-comment-response-single-edit__main"><span>登录</span>后参与评论</div></div></div><div class="cdc-comment-response__toolbar"><div class="cdc-comment-response__number">0<!-- --> 条评论</div><div class="cdc-comment-response__segment"><div class="cdc-comment-response__segment-item is-active">热度</div><div class="cdc-comment-response__segment-item">最新</div></div></div><div class="cdc-comment-response-inner"><div class="cdc-comment-response__body"><div><div class="cdc-loading"><div class="cdc-loading__inner"><div class="cdc-loading__item one"></div><div class="cdc-loading__item two"></div><div class="cdc-loading__item three"></div></div></div></div></div></div><div class="cdc-operate-footer"><div class="cdc-operate-footer__inner"><div class="cdc-operate-footer__toggle is-logout"><div class="cdc-operate-footer__toggle-text"><span>登录 </span>后参与评论</div></div></div></div></div></div></div><div class="mod-article-content recommend"><div class="mod-relevant" qct-area="推荐阅读" qct-exposure=""><div class="mod-relevant__title recommend-read">推荐阅读</div><div class="t-divider t-divider--horizontal" style="margin-bottom:0;margin-top:10px"></div></div></div></div><div class="cdc-layout__side"><div class="cdc-personal-info2 mod-author"><div class="cdc-personal-info2__inner"><div class="cdc-personal-info2__detail"><div class="cdc-personal-info2__main"><div class="cdc-personal-info2__name"><a href="/developer/user/1444933" target="_blank" class="cdc-personal-info2__name-text"></a></div><div class="cdc-personal-info2__level"><div class="cdc-personal-info2__level-number">LV.</div><div class="cdc-emblems cdc-personal-info2__level-emblems"></div></div><div class="cdc-personal-info2__position"></div></div><div class="cdc-personal-info2__avatar"></div></div><div class="cdc-personal-info2__list"><a class="cdc-personal-info2__item" href="/developer/user/undefined/articles" target="_blank"><div class="cdc-personal-info2__item-text">文章</div><div class="cdc-personal-info2__item-number">0</div></a><a class="cdc-personal-info2__item" href="/developer/user/undefined" target="_blank"><div class="cdc-personal-info2__item-text">获赞</div><div class="cdc-personal-info2__item-number">0</div></a></div></div></div><div class="mod-sticky-act"><div class="cdc-directory is-just-commercial"><div class="cdc-directory__wrap"><div class="cdc-directory__inner"><div class="cdc-directory__hd">目录</div><div class="cdc-directory__bd"><div class="cdc-directory__bd-box"><ul class="cdc-directory__list level-1"><li class="cdc-directory__item"><span class="cdc-directory__target" id="menu-24rhp">概要</span></li><li class="cdc-directory__item"><span class="cdc-directory__target" id="menu-alp3n">作用</span></li><li class="cdc-directory__item"><span class="cdc-directory__target" id="menu-2ulip">原理</span><ul class="cdc-directory__list level-2"><li class="cdc-directory__item"><span class="cdc-directory__target" id="menu-bvt0b">使用</span><ul class="cdc-directory__list level-3"></ul></li><li class="cdc-directory__item"><span class="cdc-directory__target" id="menu-ed8lt">继承关系</span><ul class="cdc-directory__list level-3"></ul></li><li class="cdc-directory__item"><span class="cdc-directory__target" id="menu-b7a32">提交任务</span><ul class="cdc-directory__list level-3"></ul></li><li class="cdc-directory__item"><span class="cdc-directory__target" id="menu-61bp8">FutureTask的属性/状态</span><ul class="cdc-directory__list level-3"></ul></li><li class="cdc-directory__item"><span class="cdc-directory__target" id="menu-c2s51">run方法</span><ul class="cdc-directory__list level-3"><li class="cdc-directory__item"><span class="cdc-directory__target" id="menu-c2s51">setException方法</span></li><li class="cdc-directory__item"><span class="cdc-directory__target" id="menu-c2s51">set方法</span></li><li class="cdc-directory__item"><span class="cdc-directory__target" id="menu-c2s51">COMPLETING状态?</span></li></ul></li><li class="cdc-directory__item"><span class="cdc-directory__target" id="menu-5dnh2">get方法</span><ul class="cdc-directory__list level-3"><li class="cdc-directory__item"><span class="cdc-directory__target" id="menu-5dnh2">WaitNode链表</span></li><li class="cdc-directory__item"><span class="cdc-directory__target" id="menu-5dnh2">awaitDone方法</span></li><li class="cdc-directory__item"><span class="cdc-directory__target" id="menu-5dnh2">report方法</span></li></ul></li><li class="cdc-directory__item"><span class="cdc-directory__target" id="menu-6q5g0">cancel方法</span><ul class="cdc-directory__list level-3"></ul></li></ul></li><li class="cdc-directory__item"><span class="cdc-directory__target" id="menu-3jd90">缺点</span></li><li class="cdc-directory__item"><span class="cdc-directory__target" id="menu-b3cih">总结</span></li></ul></div></div></div></div></div><div class="cdc-mod-product2"><div class="cdc-card" qct-exposure="" qct-area="相关产品与服务"><div class="cdc-card__inner"><div class="cdc-card__hd"><div class="cdc-card__title">相关产品与服务</div></div><div class="cdc-card__bd"><div class="cdc-product-info2__list"><div class="cdc-product-info2"><div class="cdc-product-info2__card-main"><div class="cdc-product-info2__card-name">腾讯云代码分析</div><div class="cdc-product-info2__card-desc">腾讯云代码分析(内部代号CodeDog)是集众多代码分析工具的云原生、分布式、高性能的代码综合分析跟踪管理平台,其主要功能是持续跟踪分析代码,观测项目代码质量,助力维护团队卓越代码文化。</div><div class="cdc-product-info2__card-list"><a target="_blank" href="https://cloud.tencent.com/product/tcap?from=21341&from_column=21341"><i class="product-icon introduce-icon"></i>产品介绍</a><a target="_blank" href="https://cloud.tencent.com/document/product/1460?from=21342&from_column=21342"><i class="product-icon document-icon"></i>产品文档</a></div></div><div class="cdc-product-info2__activity"><a target="_blank" href="https://cloud.tencent.com/act/pro/double11-2024?from=21344&from_column=21344"><i class="hot-icon"></i>11.11 上云拼团GO</a></div></div></div></div></div></div></div></div></div></div></div></div><div class="cdc-widget-global"><div class="cdc-widget-global__btn announcement"></div><div class="cdc-widget-global__btn code"><div class="cdc-widget-global__btn-tag">领券</div></div><div class="cdc-widget-global__btn top" style="visibility:hidden"></div></div><div class="cdc-footer"><div class="cdc-footer__inner"><div class="cdc-footer__main"><div class="cdc-footer__website"><ul class="cdc-footer__website-group"><li class="cdc-footer__website-column"><div class="cdc-footer__website-box"><h3 class="cdc-footer__website-title">社区</h3><ul class="cdc-footer__website-list"><li class="cdc-footer__website-item"><a href="/developer/column">技术文章</a></li><li class="cdc-footer__website-item"><a href="/developer/ask">技术问答</a></li><li class="cdc-footer__website-item"><a href="/developer/salon">技术沙龙</a></li><li class="cdc-footer__website-item"><a href="/developer/video">技术视频</a></li><li class="cdc-footer__website-item"><a href="/developer/learning">学习中心</a></li><li class="cdc-footer__website-item"><a href="/developer/techpedia">技术百科</a></li><li class="cdc-footer__website-item"><a href="/developer/zone/list">技术专区</a></li></ul></div></li><li class="cdc-footer__website-column"><div class="cdc-footer__website-box"><h3 class="cdc-footer__website-title">活动</h3><ul class="cdc-footer__website-list"><li class="cdc-footer__website-item"><a href="/developer/support-plan">自媒体同步曝光计划</a></li><li class="cdc-footer__website-item"><a href="/developer/support-plan-invitation">邀请作者入驻</a></li><li class="cdc-footer__website-item"><a href="/developer/article/1535830">自荐上首页</a></li><li class="cdc-footer__website-item"><a href="/developer/competition">技术竞赛</a></li></ul></div></li><li class="cdc-footer__website-column"><div class="cdc-footer__website-box"><h3 class="cdc-footer__website-title">资源</h3><ul class="cdc-footer__website-list"><li class="cdc-footer__website-item"><a href="/developer/specials">技术周刊</a></li><li class="cdc-footer__website-item"><a href="/developer/tags">社区标签</a></li><li class="cdc-footer__website-item"><a href="/developer/devdocs">开发者手册</a></li><li class="cdc-footer__website-item"><a href="/lab?from=20064&from_column=20064">开发者实验室</a></li></ul></div></li><li class="cdc-footer__website-column"><div class="cdc-footer__website-box"><h3 class="cdc-footer__website-title">关于</h3><ul class="cdc-footer__website-list"><li class="cdc-footer__website-item"><a rel="nofollow" href="/developer/article/1006434">社区规范</a></li><li class="cdc-footer__website-item"><a rel="nofollow" href="/developer/article/1006435">免责声明</a></li><li class="cdc-footer__website-item"><a rel="nofollow" href="mailto:cloudcommunity@tencent.com">联系我们</a></li><li class="cdc-footer__website-item"><a rel="nofollow" href="/developer/friendlink">友情链接</a></li></ul></div></li></ul></div><div class="cdc-footer__qr"><h3 class="cdc-footer__qr-title">腾讯云开发者</h3><div class="cdc-footer__qr-object"><img src="https://qcloudimg.tencent-cloud.cn/raw/a8907230cd5be483497c7e90b061b861.png?imageView2/2/w/76" class="cdc-footer__qr-image" alt="扫码关注腾讯云开发者"/></div><div class="cdc-footer__qr-infos"><p class="cdc-footer__qr-info"><span class="cdc-footer__qr-text">扫码关注腾讯云开发者</span></p><p class="cdc-footer__qr-info"><span class="cdc-footer__qr-text">领取腾讯云代金券</span></p></div></div></div><div class="cdc-footer__recommend"><div class="cdc-footer__recommend-rows"><div class="cdc-footer__recommend-cell"><h3 class="cdc-footer__recommend-title">热门产品</h3><div class="cdc-footer__recommend-wrap"><ul class="cdc-footer__recommend-list"><li class="cdc-footer__recommend-item"><a class="com-2-footer-recommend-link" href="https://dnspod.cloud.tencent.com?from=20064&from_column=20064">域名注册</a></li><li class="cdc-footer__recommend-item"><a class="com-2-footer-recommend-link" href="/product/cvm?from=20064&from_column=20064">云服务器</a></li><li class="cdc-footer__recommend-item"><a class="com-2-footer-recommend-link" href="/product/tbaas?from=20064&from_column=20064">区块链服务</a></li><li class="cdc-footer__recommend-item"><a class="com-2-footer-recommend-link" href="/product/mq?from=20064&from_column=20064">消息队列</a></li><li class="cdc-footer__recommend-item"><a class="com-2-footer-recommend-link" href="/product/dsa?from=20064&from_column=20064">网络加速</a></li><li class="cdc-footer__recommend-item"><a class="com-2-footer-recommend-link" href="/product/tencentdb-catalog?from=20064&from_column=20064">云数据库</a></li><li class="cdc-footer__recommend-item"><a class="com-2-footer-recommend-link" href="/product/cns?from=20064&from_column=20064">域名解析</a></li><li class="cdc-footer__recommend-item"><a class="com-2-footer-recommend-link" href="/product/cos?from=20064&from_column=20064">云存储</a></li><li class="cdc-footer__recommend-item"><a class="com-2-footer-recommend-link" href="/product/css?from=20064&from_column=20064">视频直播</a></li></ul></div></div><div class="cdc-footer__recommend-cell"><h3 class="cdc-footer__recommend-title">热门推荐</h3><div class="cdc-footer__recommend-wrap"><ul class="cdc-footer__recommend-list"><li class="cdc-footer__recommend-item"><a class="com-2-footer-recommend-link" href="/product/facerecognition?from=20064&from_column=20064">人脸识别</a></li><li class="cdc-footer__recommend-item"><a class="com-2-footer-recommend-link" href="/product/tm?from=20064&from_column=20064">腾讯会议</a></li><li class="cdc-footer__recommend-item"><a class="com-2-footer-recommend-link" href="/act/pro/enterprise2019?from=20064&from_column=20064">企业云</a></li><li class="cdc-footer__recommend-item"><a class="com-2-footer-recommend-link" href="/product/cdn-scd?from=20064&from_column=20064">CDN加速</a></li><li class="cdc-footer__recommend-item"><a class="com-2-footer-recommend-link" href="/product/trtc?from=20064&from_column=20064">视频通话</a></li><li class="cdc-footer__recommend-item"><a class="com-2-footer-recommend-link" href="/product/tiia?from=20064&from_column=20064">图像分析</a></li><li class="cdc-footer__recommend-item"><a class="com-2-footer-recommend-link" href="/product/cdb?from=20064&from_column=20064">MySQL 数据库</a></li><li class="cdc-footer__recommend-item"><a class="com-2-footer-recommend-link" href="/product/symantecssl?from=20064&from_column=20064">SSL 证书</a></li><li class="cdc-footer__recommend-item"><a class="com-2-footer-recommend-link" href="/product/asr?from=20064&from_column=20064">语音识别</a></li></ul></div></div><div class="cdc-footer__recommend-cell"><h3 class="cdc-footer__recommend-title">更多推荐</h3><div class="cdc-footer__recommend-wrap"><ul class="cdc-footer__recommend-list"><li class="cdc-footer__recommend-item"><a class="com-2-footer-recommend-link" href="/solution/data_protection?from=20064&from_column=20064">数据安全</a></li><li class="cdc-footer__recommend-item"><a class="com-2-footer-recommend-link" href="/product/clb?from=20064&from_column=20064">负载均衡</a></li><li class="cdc-footer__recommend-item"><a class="com-2-footer-recommend-link" href="/product/sms?from=20064&from_column=20064">短信</a></li><li class="cdc-footer__recommend-item"><a class="com-2-footer-recommend-link" href="/product/ocr?from=20064&from_column=20064">文字识别</a></li><li class="cdc-footer__recommend-item"><a class="com-2-footer-recommend-link" href="/product/vod?from=20064&from_column=20064">云点播</a></li><li class="cdc-footer__recommend-item"><a class="com-2-footer-recommend-link" href="https://tm.cloud.tencent.com?from=20064&from_column=20064">商标注册</a></li><li class="cdc-footer__recommend-item"><a class="com-2-footer-recommend-link" href="/solution/la?from=20064&from_column=20064">小程序开发</a></li><li class="cdc-footer__recommend-item"><a class="com-2-footer-recommend-link" href="/product/cat?from=20064&from_column=20064">网站监控</a></li><li class="cdc-footer__recommend-item"><a class="com-2-footer-recommend-link" href="/product/cdm?from=20064&from_column=20064">数据迁移</a></li></ul></div></div></div></div><div class="cdc-footer__copyright"><div class="cdc-footer__copyright-text"><p>Copyright © 2013 - <!-- -->2024<!-- --> Tencent Cloud. All Rights Reserved. 腾讯云 版权所有 </p><p>深圳市腾讯计算机系统有限公司 ICP备案/许可证号:<a href="https://beian.miit.gov.cn/#/Integrated/index" target="_blank">粤B2-20090059 </a><a href="https://www.beian.gov.cn/portal/index.do" target="_blank">深公网安备号 44030502008569</a></p><p>腾讯云计算(北京)有限责任公司 京ICP证150476号 | <a href="https://beian.miit.gov.cn/#/Integrated/index" target="_blank">京ICP备11018762号</a> <!-- -->|<!-- --> <a href="https://www.beian.gov.cn/portal/index.do" target="_blank">京公网安备号11010802020287</a></p></div></div></div></div><div style="display:none"><a href="/developer/ask/archives.html">问题归档</a><a href="/developer/column/archives.html">专栏文章</a><a href="/developer/news/archives.html">快讯文章归档</a><a href="/developer/information/all.html">关键词归档</a><a href="/developer/devdocs/archives.html">开发者手册归档</a><a href="/developer/devdocs/sections_p1.html">开发者手册 Section 归档</a></div><div class="cdc-m-footer"><div class="cdc-m-footer__inner"><div class="cdc-m-footer__copyright"><p>Copyright © 2013 - <!-- -->2024<!-- --> Tencent Cloud.</p><p>All Rights Reserved. 腾讯云 版权所有</p></div></div></div><div class="cdc-operate-footer"><div class="cdc-operate-footer__inner"><div class="cdc-operate-footer__toggle is-logout"><div class="cdc-operate-footer__toggle-text"><span>登录 </span>后参与评论</div></div><div class="cdc-operate-footer__operations"><div class="cdc-operate-footer__operate"><i class="cdc-operate-footer__operate-icon comment"></i></div><div class="cdc-operate-footer__operate emoji"><div class="emoji-item"><span class="emoji-item-icon fight"></span></div></div><div class="cdc-operate-footer__operate"><i class="cdc-operate-footer__operate-icon book"></i></div><div class="cdc-operate-footer__operate"><i class="cdc-operate-footer__operate-icon menu"></i></div><div class="cdc-operate-footer__operate"><i class="cdc-operate-footer__operate-icon more"></i></div></div></div></div><div class="cdc-suspend-pill"><div class="cdc-suspend-pill__inner"><button class="cdc-icon-btn cdc-suspend-pill__item emoji cdc-icon-btn--text"><div class="emoji-item"><span class="emoji-item-icon fight"></span></div><span class="cdc-suspend-pill__item-number">0</span></button><button class="cdc-icon-btn cdc-suspend-pill__item like cdc-icon-btn--text"><span class="cdc-svg-icon-con"><span class="cdc-svg-icon" style="width:24px;height:24px"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentcolor"><path fill-rule="evenodd" clip-rule="evenodd" d="M17.5 11.25C17.5 11.9404 16.9404 12.5 16.25 12.5C15.5596 12.5 15 11.9404 15 11.25C15 10.5596 15.5596 10 16.25 10C16.9404 10 17.5 10.5596 17.5 11.25Z M12.25 12.5C12.9404 12.5 13.5 11.9404 13.5 11.25C13.5 10.5596 12.9404 10 12.25 10C11.5596 10 11 10.5596 11 11.25C11 11.9404 11.5596 12.5 12.25 12.5Z M8.25 12.5C8.94036 12.5 9.5 11.9404 9.5 11.25C9.5 10.5596 8.94036 10 8.25 10C7.55964 10 7 10.5596 7 11.25C7 11.9404 7.55964 12.5 8.25 12.5Z M5 3C3.34315 3 2 4.34315 2 6V16C2 17.6569 3.34315 19 5 19H8.34311L10.5858 21.2426C11.3668 22.0237 12.6331 22.0237 13.4142 21.2426L15.6568 19H19C20.6569 19 22 17.6569 22 16V6C22 4.34315 20.6569 3 19 3H5ZM4 6C4 5.44772 4.44772 5 5 5H19C19.5523 5 20 5.44772 20 6V16C20 16.5523 19.5523 17 19 17H14.8284L12 19.8284L9.17154 17H5C4.44772 17 4 16.5523 4 16V6Z"></path></svg></span></span><span class="cdc-suspend-pill__item-number">0</span></button><button class="cdc-icon-btn cdc-suspend-pill__item collect cdc-icon-btn--text" qct-area="收藏文章" qct-click=""><span class="cdc-svg-icon-con"><span class="cdc-svg-icon" style="width:24px;height:24px"><svg width="24" height="24" viewBox="0 0 24 24" fill="currentcolor" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.2057 3.11487C10.9393 1.62838 13.059 1.62838 13.7927 3.11487L15.9724 7.53141L20.8463 8.23963C22.4867 8.478 23.1418 10.4939 21.9547 11.651L18.4279 15.0888L19.2605 19.9431C19.5407 21.5769 17.8258 22.8228 16.3586 22.0514L11.9992 19.7596L7.63981 22.0514C6.17255 22.8228 4.45769 21.5769 4.73791 19.9431L5.57048 15.0888L2.04366 11.651C0.856629 10.4939 1.51165 8.478 3.15209 8.23963L8.02603 7.53141L10.2057 3.11487ZM11.9992 4L9.8195 8.41654C9.52818 9.00683 8.96504 9.41597 8.31363 9.51062L3.43969 10.2188L6.9665 13.6566C7.43787 14.1161 7.65297 14.7781 7.5417 15.4269L6.70913 20.2812L11.0685 17.9893C11.6512 17.683 12.3472 17.683 12.9299 17.9893L17.2893 20.2812L16.4567 15.4269C16.3454 14.7781 16.5605 14.1161 17.0319 13.6566L20.5587 10.2188L15.6848 9.51062C15.0333 9.41597 14.4702 9.00683 14.1789 8.41654L11.9992 4Z"></path></svg></span></span><span class="cdc-suspend-pill__item-number">0</span></button><button class="cdc-icon-btn cdc-suspend-pill__item cdc-icon-btn--text"><span class="cdc-svg-icon-con"><span class="cdc-svg-icon" style="width:24px;height:24px"><svg width="24" height="24" viewBox="0 0 24 24" fill="currentcolor" xmlns="http://www.w3.org/2000/svg"><path d="M13.0001 4V6H17.5859L10.1787 13.4072L11.6043 14.81L19.0001 7.41424V12H21.0001V4H13.0001Z"></path><path d="M3 12.9996C3 8.71646 5.99202 5.13211 10 4.22266V6.28952C7.10851 7.15007 5 9.82862 5 12.9996C5 16.8656 8.13401 19.9996 12 19.9996C15.1709 19.9996 17.8494 17.8912 18.71 14.9999H20.7769C19.8674 19.0077 16.2831 21.9996 12 21.9996C7.02944 21.9996 3 17.9702 3 12.9996Z"></path></svg></span></span></button><button class="cdc-icon-btn cdc-suspend-pill__item cdc-icon-btn--text"><span class="cdc-svg-icon-con"><span class="cdc-svg-icon" style="width:24px;height:24px"><svg width="24" height="24" viewBox="0 0 24 24" fill="currentcolor" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M2 6C2 4.34315 3.34315 3 5 3H17C18.6569 3 20 4.34315 20 6V11H18V6C18 5.44772 17.5523 5 17 5H5C4.44772 5 4 5.44772 4 6V18C4 18.5523 4.44772 19 5 19H12V21H5C3.34315 21 2 19.6569 2 18V6ZM6 8H12V10H6V8ZM6 12H15V14H6V12ZM22 16H19V13H17V16H14V18H17V21H19V18H22V16Z"></path></svg></span></span></button><div class="cdc-suspend-pill__line"></div><button class="cdc-icon-btn cdc-suspend-pill__item cdc-icon-btn--text"><span class="cdc-svg-icon-con"><span class="cdc-svg-icon" style="width:24px;height:24px"><svg width="24" height="24" viewBox="0 0 24 24" fill="currentcolor" xmlns="http://www.w3.org/2000/svg"><path d="M16.5047 6H13V4H20V10.876H18V7.33313L14.4571 10.876L13.0429 9.46182L16.5047 6Z"></path><path d="M11 6.00006H7.4953L10.9571 9.46189L9.54291 10.8761L6 7.33319V10.8761H4V4.00006H11V6.00006Z"></path><path d="M7.4953 18.8761H11V20.8761H4V14.0001H6V17.543L9.54291 14.0001L10.9571 15.4143L7.4953 18.8761Z"></path><path d="M16.5047 18.8761H13V20.8761H20V14.0001H18V17.543L14.4571 14.0001L13.0429 15.4143L16.5047 18.8761Z"></path></svg></span></span></button><button class="cdc-icon-btn cdc-suspend-pill__item recommend cdc-icon-btn--text" track-click="{"areaId":106019,"recPolicyId":1002,"elementId":2}" track-exposure="{"areaId":106019,"recPolicyId":1002,"elementId":2}"><span class="cdc-svg-icon-con"><span class="cdc-svg-icon" style="width:24px;height:24px"><svg width="24" height="24" viewBox="0 0 24 24" fill="currentcolor" xmlns="http://www.w3.org/2000/svg"><path d="M5 8H10V10H5V8Z"></path><path d="M10 12H5V14H10V12Z"></path><path d="M14 8H19V10H14V8Z"></path><path d="M19 12H14V14H19V12Z"></path><path fill-rule="evenodd" clip-rule="evenodd" d="M11 20.608L9.57047 20.1996C8.83303 19.9889 8.05701 19.9506 7.30243 20.0878L4.35777 20.6232C3.13009 20.8464 2 19.9033 2 18.6555V5.2669C2 4.2325 2.78877 3.36877 3.81893 3.27512L6.52892 3.02875C7.95704 2.89892 9.39058 3.21084 10.6356 3.9223L12 4.70194L13.3644 3.9223C14.6094 3.21084 16.043 2.89892 17.4711 3.02875L20.1811 3.27512C21.2112 3.36877 22 4.2325 22 5.2669V18.6555C22 19.9033 20.8699 20.8464 19.6422 20.6232L16.6976 20.0878C15.943 19.9506 15.167 19.9889 14.4295 20.1996L13 20.608L12.5 20.8535L12 20.8937L11.5 20.8535L11 20.608ZM6.70999 5.02054C7.73007 4.9278 8.75403 5.1506 9.64336 5.65879L11 6.43401V18.528L10.1199 18.2765C9.0875 17.9815 8.00107 17.928 6.94466 18.1201L4 18.6555V5.2669L6.70999 5.02054ZM13 18.528L13.8801 18.2765C14.9125 17.9815 15.9989 17.928 17.0553 18.1201L20 18.6555V5.2669L17.29 5.02054C16.2699 4.9278 15.246 5.1506 14.3566 5.65879L13 6.43401V18.528Z"></path></svg></span></span><span class="cdc-suspend-pill__item-text">推荐</span></button></div></div></div></div></div><script> if (!String.prototype.replaceAll) { String.prototype.replaceAll = function (str, newStr) { // If a regex pattern if (Object.prototype.toString.call(str).toLowerCase() === '[object regexp]') { return this.replace(str, newStr); } // If a string return this.replace(new RegExp(str, 'g'), newStr); }; } </script><script src="https://developer.qcloudimg.com/static/jquery.min.js"></script><script src="https://cloud.tencent.com/qccomponent/login/api.js"></script><script src="https://cloudcache.tencent-cloud.com/qcloud/main/scripts/release/common/vendors/react/react.16.8.6.min.js"></script><script src="https://web.sdk.qcloud.com/player/tcplayer/release/v4.5.1/libs/TXLivePlayer-1.2.0.min.js" defer=""></script><script src="https://cloudcache.tencent-cloud.com/open/qcloud/video/tcplayer/libs/hls.min.0.13.2m.js"></script><script src="https://cloudcache.tencent-cloud.com/open/qcloud/video/tcplayer/tcplayer.v4.1.min.js"></script><script id="__NEXT_DATA__" type="application/json">{"props":{"isMobile":false,"isSupportWebp":false,"currentDomain":"cloud.tencent.com","baseUrl":"https://cloud.tencent.com","reqId":"uPUIjE-rSXEfDBRMF3e2N","query":{"articleId":"1680378"},"platform":"other","env":"production","__N_SSP":true,"pageProps":{"fallback":{"#url:\"/api/article/detail\",params:#articleId:1680378,,":{"articleData":{"articleId":1680378,"codeLineNum":285,"readingTime":583,"wordsNum":2674},"articleInfo":{"articleId":1680378,"channel":2,"commentNum":0,"content":{"entityMap":{"0":{"type":"LINK","mutability":"MUTABLE","data":{"url":"https://xtboke.cn/tag-%E6%BA%90%E7%A0%81.html"}},"1":{"type":"IMAGE","mutability":"IMMUTABLE","data":{"imageUrl":"https://ask.qcloudimg.com/http-save/yehe-1444933/6ske3hyobj.png","imageAlt":"upload successful","blockWidth":788,"blockHeight":212}},"2":{"type":"IMAGE","mutability":"IMMUTABLE","data":{"imageUrl":"https://ask.qcloudimg.com/http-save/yehe-1444933/9xbcz2r4ih.png","imageAlt":"upload successful","blockWidth":1214,"blockHeight":386}},"3":{"type":"IMAGE","mutability":"IMMUTABLE","data":{"imageUrl":"https://ask.qcloudimg.com/http-save/yehe-1444933/095h7lczvv.png","imageAlt":"upload successful","blockWidth":1206,"blockHeight":494}},"4":{"type":"LINK","mutability":"MUTABLE","data":{"url":"https://xtboke.cn/tag-repo.html"}},"5":{"type":"LINK","mutability":"MUTABLE","data":{"url":"http://jcip.net/listings/Memoizer.java"}}},"blocks":[{"key":"24rhp","text":"概要","type":"header-two","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{"text":"%E6%A6%82%E8%A6%81"}},{"key":"8grr","text":"Future是一种异步计算的模式,本文带你理解一下什么是Future,以及基本的FutureTask的实现原理。","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"alp3n","text":"作用","type":"header-two","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{"text":"%E4%BD%9C%E7%94%A8"}},{"key":"6bsv4","text":"如果在一个方法中要执行另一个操作(任务),但是这个操作会耗时很久,而且你后面还需要用到这个操作的返回结果或者必须等到这个操作结束你才能走下去,你会怎样做?可能大家都会想到异步去执行,即新建一个线程去做这个事情,但是这样的话,你后面的操作就要放到这个异步线程那里,你的方法就变成异步的了,对你原来的返回造成了影响。\n这时候,Future就发挥作用了,有些地方说它是一种模式,其实,它就是对一个异步操作的封装,它会返回一个\"凭证\"给你,你可以用这个\"凭证\"在需要的时候获取到这个异步操作的结果,一般来说这个\"凭证\"就是future。","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"2ulip","text":"原理","type":"header-two","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{"text":"%E5%8E%9F%E7%90%86"}},{"key":"b0pdh","text":"FutureTask就是Future的基本实现,下面我们就从代码分析一下实现的原理。\n源码基本JDK1.8。","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[{"offset":43,"length":2,"key":0}],"data":{}},{"key":"3pl2f","text":"Future接口","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"1ik29","text":"我们先看看Future的定义,即你拿到这个\"凭证\"之后你能干点什么。","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"1tb3e","text":"public interface Future\u003cV\u003e {\n\n //取消这次任务\n boolean cancel(boolean mayInterruptIfRunning);\n //看看是否取消了\n boolean isCancelled();\n //看看是否完成了\n boolean isDone();\n //获取结果\n V get() throws InterruptedException, ExecutionException;\n //时间内获取结果,超时则抛异常\n V get(long timeout, TimeUnit unit)\n throws InterruptedException, ExecutionException, TimeoutException;\n}","type":"code-block","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{"syntax":"javascript"}},{"key":"bvt0b","text":"使用","type":"header-three","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{"text":"%E4%BD%BF%E7%94%A8"}},{"key":"eaus0","text":"如果没用过的,这里简单演示一下Future怎么使用,大家有个感性认识。","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"admbd","text":"private static ExecutorService threadPool = Executors.newCachedThreadPool();\n\n public static void main(String[] args) throws Exception {\n //通过线程池提交任务,并返回一个future\n Future\u003cString\u003e future = threadPool.submit(new AsyncTask());\n //通过future获取结果。get之前一直阻塞直到有结果返回。\n String result = future.get();\n System.out.println(result);\n }\n\n public class AsyncTask implements Callable\u003cString\u003e {\n\n @Override\n public String call() throws Exception {\n TimeUnit.SECONDS.sleep(5);\n return \"ok\";\n }\n }","type":"code-block","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{"syntax":"javascript"}},{"key":"ed8lt","text":"继承关系","type":"header-three","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{"text":"%E7%BB%A7%E6%89%BF%E5%85%B3%E7%B3%BB"}},{"key":"2ramt","text":"?","type":"atomic","depth":0,"inlineStyleRanges":[],"entityRanges":[{"offset":0,"length":1,"key":1}],"data":{}},{"key":"2575j","text":"FutureTask是一个RunnableFuture,这个很好理解,就是Runnable+Future了。","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"b7a32","text":"提交任务","type":"header-three","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{"text":"%E6%8F%90%E4%BA%A4%E4%BB%BB%E5%8A%A1"}},{"key":"4do6f","text":"从任务的提交入手分析源码。\nAbstractExecutorService的submit方法。","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"5r2r1","text":"public \u003cT\u003e Future\u003cT\u003e submit(Callable\u003cT\u003e task) {\n if (task == null) throw new NullPointerException();\n //这里封装了一下callable变成一个RunnableFuture\n RunnableFuture\u003cT\u003e ftask = newTaskFor(task);\n //注意线程池执行的是RunnableFuture,因为这个Future继承Runnable,所以它是可执行的。\n execute(ftask);\n //返回future\n return ftask;\n }","type":"code-block","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{"syntax":"javascript"}},{"key":"3pt1o","text":"submit方法也是支持Runnable的。ExecutorService内部会把Runnable转成Callable,只不过Runnable的返回值为null。","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"61bp8","text":"FutureTask的属性/状态","type":"header-three","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{"text":"FutureTask%E7%9A%84%E5%B1%9E%E6%80%A7/%E7%8A%B6%E6%80%81"}},{"key":"9l1cv","text":"先看下FutureTask的一些内部属性,才好了解它是怎么运行的。","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"cn8bm","text":"//重要属性\"状态\"state定义为volatile,为了在高并发下能够获取到最新的值\nprivate volatile int state;\n //为state定义了7个状态,看名字都挺好了解的。\n private static final int NEW = 0;\n private static final int COMPLETING = 1;\n //正常结束\n private static final int NORMAL = 2;\n private static final int EXCEPTIONAL = 3;\n private static final int CANCELLED = 4;\n private static final int INTERRUPTING = 5;\n private static final int INTERRUPTED = 6;\n\n //状态之间的转换\n * Possible state transitions:\n * NEW -\u003e COMPLETING -\u003e NORMAL\n * NEW -\u003e COMPLETING -\u003e EXCEPTIONAL\n * NEW -\u003e CANCELLED\n * NEW -\u003e INTERRUPTING -\u003e INTERRUPTED\n */\n\n //用户提交的真正任务\n private Callable\u003cV\u003e callable;\n //返回结果\n private Object outcome; // non-volatile, protected by state reads/writes\n //记录跑任务的那个线程,只有一个在运行。取消时可以中断这个线程的行为。\n private volatile Thread runner;\n /** Treiber stack of waiting threads */\n //这个属性比较重要,后面讲的比较多。记录WaitNode链表的头部,volatile。WaitNode链表是等待结果的线程集合,即这个任务还没跑完时,但同时有很多持有这个future的线程调用了get方法获取结果。\n private volatile WaitNode waiters;","type":"code-block","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{"syntax":"javascript"}},{"key":"c2s51","text":"run方法","type":"header-three","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{"text":"run%E6%96%B9%E6%B3%95"}},{"key":"2obus","text":"当这个RunnableFuture提交到线程池后,它做了什么。","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"ek2hc","text":"public void run() {\n //为了防止future重复运行,需要判断是NEW状态。\n //同时记录runner属性\n //这里UNSAFE的CAS操作在JUC里用的比较多,不展开了(我的原则是,不是这个话题的内容不过多展开,保持专注和精简。)\n if (state != NEW ||\n !UNSAFE.compareAndSwapObject(this, runnerOffset,\n null, Thread.currentThread()))\n return;\n try {\n Callable\u003cV\u003e c = callable;\n if (c != null \u0026\u0026 state == NEW) {\n V result;\n boolean ran;\n try {\n //执行用户的callable\n result = c.call();\n ran = true;\n } catch (Throwable ex) {\n result = null;\n ran = false;\n //如果callable运行异常了,这里会把这个异常吃掉,然后调用setException方法\n setException(ex);\n }\n if (ran)\n //正常结束就是设置结果\n set(result);\n }\n } finally {\n // runner must be non-null until state is settled to\n // prevent concurrent calls to run()\n runner = null;\n // state must be re-read after nulling runner to prevent\n // leaked interrupts\n int s = state;\n if (s \u003e= INTERRUPTING)\n handlePossibleCancellationInterrupt(s);\n }\n }","type":"code-block","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{"syntax":"javascript"}},{"key":"1gbp5","text":"值得注意的是,如果原来的callable任务运行异常了,那么在run方法中会直接catch掉,然后在get的时候才抛出来。这么也是为了做错误隔离,为了callable的异常不会影响到future的运行。","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"b6i9c","text":"setException方法","type":"header-four","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{"text":"setException%E6%96%B9%E6%B3%95"}},{"key":"6o17r","text":"protected void setException(Throwable t) {\n if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {\n //把结果设为异常\n outcome = t;\n //更新状态为EXCEPTIONAL\n UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state\n //finishCompletion作为一个结束动作\n finishCompletion();\n }\n }","type":"code-block","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{"syntax":"javascript"}},{"key":"85gvg","text":"set方法","type":"header-four","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{"text":"set%E6%96%B9%E6%B3%95"}},{"key":"9cqjg","text":"protected void set(V v) {\n if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {\n //设置结果\n outcome = v;\n //更新状态为NORMAL\n UNSAFE.putOrderedInt(this, stateOffset, NORMAL);\n //同样调用了finishCompletion方法\n finishCompletion();\n }\n }","type":"code-block","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{"syntax":"javascript"}},{"key":"27e8e","text":"setException方法和set方法都是protected,不能随意调用,不过子类可以改变它的行为。","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"cb1ci","text":"COMPLETING状态?","type":"header-four","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{"text":"COMPLETING%E7%8A%B6%E6%80%81%EF%BC%9F"}},{"key":"4sq27","text":"在上面说到的7个状态中有一个COMPLETING的状态,它表示新建NEW和正常结束NORMAL或异常结束EXCEPTIONAL中间的这么一个状态,在set和setException用到了,会先把NEW状态更新为COMPLETING,再把COMPLETING更新为对应的结果状态。\n刚开始我认为这个状态是没必要的。因为这个FutureTask只会有一个线程在运行它,不存在竞争,而且看代码也知道,作者没对竞争失败做处理,那么set和setException的CAS操作是肯定会成功的,所以我觉得把COMPLETING变成NEW也是可以的。但是细想如果直接把","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"4ig0j","text":"UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)","type":"code-block","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{"syntax":"javascript"}},{"key":"7e69a","text":"变成","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"c2f8","text":"UNSAFE.compareAndSwapInt(this, stateOffset, NEW, NORMAL)","type":"code-block","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{"syntax":"javascript"}},{"key":"1d5fi","text":"但是后面还有一步赋值操作。","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"bvosn","text":"outcome = v","type":"code-block","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{"syntax":"javascript"}},{"key":"45msf","text":"并发下,这时如果有其他线程在CAS后想获取结果,就返回null了。","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"1ld5d","text":"finishCompletion方法","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"322r4","text":"//如果这个future正常结束,异常结束,被取消了,都会调用这个方法。\nprivate void finishCompletion() {\n // assert state \u003e COMPLETING;\n //这里会不停的拿头部节点做遍历,直到头部节点为null。这是为了防止在并发下有新的节点新插入进来。\n for (WaitNode q; (q = waiters) != null;) {\n //CAS把WaitNode链表的头部设为null。\n if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {\n for (;;) {\n Thread t = q.thread;\n if (t != null) {\n q.thread = null;\n //唤醒WaitNode的线程,唤醒的线程继续在awaitDone方法里做循环。\n LockSupport.unpark(t);\n }\n WaitNode next = q.next;\n //直到next为null,完成链表的遍历\n if (next == null)\n break;\n q.next = null; // unlink to help gc\n q = next;\n }\n break;\n }\n }\n //这个done方法是预留方法,子类可以继承它来做点别的。\n done();\n\n callable = null; // to reduce footprint\n }","type":"code-block","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{"syntax":"javascript"}},{"key":"5dnh2","text":"get方法","type":"header-three","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{"text":"get%E6%96%B9%E6%B3%95"}},{"key":"29f0g","text":"get方法是重点。\n因为作者设计FutureTask是支持高并发的,而且用了Lock-Free无锁算法,所以阅读起来会比较费劲。","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"erlc3","text":"public V get() throws InterruptedException, ExecutionException {\n int s = state;\n if (s \u003c= COMPLETING)\n s = awaitDone(false, 0L);\n return report(s);\n }","type":"code-block","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{"syntax":"javascript"}},{"key":"358l7","text":"WaitNode链表","type":"header-four","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{"text":"WaitNode%E9%93%BE%E8%A1%A8"}},{"key":"bo60o","text":"继续看下去之前,先看看WaitNode的定义。\n很简单,只有一个Thread和next指针。Thread就是指当前需要获取future结果的那个线程。WaitNode通过next指针形成一条链表。","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"fijf8","text":"static final class WaitNode {\n volatile Thread thread;\n volatile WaitNode next;\n WaitNode() { thread = Thread.currentThread(); }\n }","type":"code-block","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{"syntax":"javascript"}},{"key":"atg83","text":"这是在Lock-Free中常见的数据结构,看上去是不是有点像AQS呢?","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"43fok","text":"/*\n * Revision notes: This differs from previous versions of this\n * class that relied on AbstractQueuedSynchronizer, mainly to\n * avoid surprising users about retaining interrupt status during\n * cancellation races. Sync control in the current design relies\n * on a \"state\" field updated via CAS to track completion, along\n * with a simple Treiber stack to hold waiting threads.\n *\n * Style note: As usual, we bypass overhead of using\n * AtomicXFieldUpdaters and instead directly use Unsafe intrinsics.\n */","type":"code-block","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{"syntax":"javascript"}},{"key":"copei","text":"实际上,官方也说了,之前版本的实现是用了AQS的,原因是...(这个原因我不是很懂是啥意思),现在改为Treiber stack算法了。","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"eahh","text":"awaitDone方法","type":"header-four","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{"text":"awaitDone%E6%96%B9%E6%B3%95"}},{"key":"c5pru","text":"private int awaitDone(boolean timed, long nanos)\n throws InterruptedException {\n final long deadline = timed ? System.nanoTime() + nanos : 0L;\n WaitNode q = null;\n boolean queued = false;\n //死循环直到s \u003e COMPLETING或者超时,当然这个不是真的死循环,大部分情况下线程是会挂起的。\n for (;;) {\n //如果线程是被中断了,则从链表移除当前节点,然后抛异常\n if (Thread.interrupted()) {\n removeWaiter(q);\n throw new InterruptedException();\n }\n\n int s = state;\n //从上面7个状态看出,当s \u003e COMPLETING都是结束的状态,要不正常结束,异常,取消等。可见合理的状态值设计带来的方便。\n if (s \u003e COMPLETING) {\n if (q != null)\n q.thread = null;\n return s;\n }\n //这里就是为了防止上面我说的,结果赋值时并发下其他线程获取不到值的情况,所以让这个线程yield一下,再做一次循环,说不定下次就是s \u003e COMPLETING呢。\n else if (s == COMPLETING) // cannot time out yet\n Thread.yield();\n else if (q == null)\n //新建一个WaitNode,准备进链表\n q = new WaitNode();\n else if (!queued)\n //CAS把WaitNode节点插入到链表的头部,如果失败则下次继续插入\n queued = UNSAFE.compareAndSwapObject(this, waitersOffset,\n q.next = waiters, q);\n //如果get方法设置了超时时间,则会进入这个分支,如果超时了,也会返回state。还没超时则挂起,挂起的时间为时间差。\n else if (timed) {\n nanos = deadline - System.nanoTime();\n if (nanos \u003c= 0L) {\n //超时需要从链表移除当前节点\n removeWaiter(q);\n return state;\n }\n LockSupport.parkNanos(this, nanos);\n }\n //注意这里,是最后的步骤,即当s \u003c COMPLETING,已经插入链表了,不是超时的情况\n else\n LockSupport.park(this);\n }\n }","type":"code-block","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{"syntax":"javascript"}},{"key":"7ps1v","text":"awaitDone方法返回的是state状态的值。\n要注意if else执行的顺序,先是判断中断状态,其次判断state的完成状态,再是新建节点,然后插入,最后才是挂起。用for循环去尝试当CAS失败的情况。","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"e5l9e","text":"插入节点的只有这个方法,所以我们可以知道,链表的结构如下:","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"5upsh","text":"?","type":"atomic","depth":0,"inlineStyleRanges":[],"entityRanges":[{"offset":0,"length":1,"key":2}],"data":{}},{"key":"mhqq","text":"removeWaiter方法的作用是当中断或超时时移除当前的WaitNode。这个方法有点不好理解。","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"6q5b8","text":"private void removeWaiter(WaitNode node) {\n if (node != null) {\n node.thread = null;\n retry:\n for (;;) { // restart on removeWaiter race\n for (WaitNode pred = null, q = waiters, s; q != null; q = s) {\n s = q.next;\n if (q.thread != null)\n pred = q;\n else if (pred != null) {\n pred.next = s;\n if (pred.thread == null) // check for race\n continue retry;\n }\n else if (!UNSAFE.compareAndSwapObject(this, waitersOffset,\n q, s))\n continue retry;\n }\n break;\n }\n }\n }","type":"code-block","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{"syntax":"javascript"}},{"key":"7e31a","text":"我们画个图,分情况来理解一下","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"6kkjd","text":"?","type":"atomic","depth":0,"inlineStyleRanges":[],"entityRanges":[{"offset":0,"length":1,"key":3}],"data":{}},{"key":"dsmtd","text":"如果q.thread != null\n因为进来时已经直接把node.thread = null,说明q已经不是当前的node,q是其他线程插入进来的node,这时需要把s,q,pred继续往左移动。","type":"ordered-list-item","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"8ch8m","text":"如果q.thread == null \u0026\u0026 pred != null\n这时可以把pred的next指向s了,即删除了q。但是如果pred.thread == null,说明pred的线程也把它自己的节点删除了(删除节点的情况除了removeWaiter,还有正常获取结果后也会),所以pred已经没用了,需要重新来找到新的pred。","type":"ordered-list-item","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"cjs0j","text":"如果q.thread == null \u0026\u0026 pred == null\n说明前面的节点都被删除了,已经没用了,把s直接置为头部。","type":"ordered-list-item","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"c6ql7","text":"report方法","type":"header-four","depth":0,"inlineStyleRanges":[],"entityRanges":[{"offset":0,"length":4,"key":4}],"data":{"text":"report%E6%96%B9%E6%B3%95"}},{"key":"3c3gg","text":"比较简单了","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"3a899","text":"private V report(int s) throws ExecutionException {\n Object x = outcome;\n if (s == NORMAL)\n //task正常执行就返回结果\n return (V)x;\n if (s \u003e= CANCELLED)\n //取消则抛异常\n throw new CancellationException();\n //否则抛出task运行的异常\n throw new ExecutionException((Throwable)x);\n }","type":"code-block","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{"syntax":"javascript"}},{"key":"6q5g0","text":"cancel方法","type":"header-three","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{"text":"cancel%E6%96%B9%E6%B3%95"}},{"key":"6mee","text":"//mayInterruptIfRunning参数,取消的同时可以中断runner线程的运行。\npublic boolean cancel(boolean mayInterruptIfRunning) {\n //状态更新为INTERRUPTING或CANCELLED\n if (!(state == NEW \u0026\u0026\n UNSAFE.compareAndSwapInt(this, stateOffset, NEW,\n mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))\n return false;\n try { // in case call to interrupt throws exception\n //中断\n if (mayInterruptIfRunning) {\n try {\n Thread t = runner;\n if (t != null)\n //调用线程的interrupt方法来中断线程\n t.interrupt();\n } finally { // final state\n UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);\n }\n }\n } finally {\n //取消也要把watiers清空掉\n finishCompletion();\n }\n return true;\n }","type":"code-block","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{"syntax":"javascript"}},{"key":"3jd90","text":"缺点","type":"header-two","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{"text":"%E7%BC%BA%E7%82%B9"}},{"key":"a6nst","text":"FutureTask有明显的下面两个缺点:","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"ddik4","text":"重复提交\n并发会有重复提交的可能,虽然在内部有对状态NEW的判断,但那只是针对那个FutureTask实例的,我们看到,在submit方法中每次提交任务都会new 一个\nFutureTask出来的。\n不过现在已经有一个解决方案Memoizer\n其实很简单,就是用一个key来记录这次的Future,然后放在一个Map里,下次用到时再从Map里取出来。","type":"ordered-list-item","depth":0,"inlineStyleRanges":[],"entityRanges":[{"offset":113,"length":8,"key":5}],"data":{}},{"key":"169rs","text":"批量任务\nFuture每次只能提交一个任务,而且获取结果之前会一直阻塞,这点也是很不友好的。","type":"ordered-list-item","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"5tfhn","text":"综上,FutureTask只是提供了一个基本的功能实现,远远不能满足要求高的我们,guava的ListenableFuture和JDK1.8的CompletableFuture都是对Future的增强,前者提供监听器处理结果,后者更加强大,提供链式调用,同步、异步结果返回不同的组合方式来帮助你处理复杂的业务场景。","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"b3cih","text":"总结","type":"header-two","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{"text":"%E6%80%BB%E7%BB%93"}},{"key":"79pmj","text":"源码部分已经介绍的7788了。因为采用了无锁算法,所以实现起来看上去代码比较复杂,看代码时要意识到这个,多想想在高并发下链表会出现怎样的情况,我没有把所有可能出现的情况都罗列出来,所以要靠读者自己多思考。","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"9dp0q","text":"总的来说,Future通过循环判断state状态,挂起、唤醒线程的操作,来实现异步阻塞,通过一个WaitNode链表来处理并发的情况。","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}}]},"createTime":1597632104,"ext":{"closeTextLink":0,"comment_ban":0,"description":"","focusRead":0},"favNum":0,"isOriginal":0,"likeNum":2,"pic":"","plain":"概要\nFuture是一种异步计算的模式,本文带你理解一下什么是Future,以及基本的FutureTask的实现原理。\n作用\n如果在一个方法中要执行另一个操作(任务),但是这个操作会耗时很久,而且你后面还需要用到这个操作的返回结果或者必须等到这个操作结束你才能走下去,你会怎样做?可能大家都会想到异步去执行,即新建一个线程去做这个事情,但是这样的话,你后面的操作就要放到这个异步线程那里,你的方法就变成异步的了,对你原来的返回造成了影响。\n这时候,Future就发挥作用了,有些地方说它是一种模式,其实,它就是对一个异步操作的封装,它会返回一个\"凭证\"给你,你可以用这个\"凭证\"在需要的时候获取到这个异步操作的结果,一般来说这个\"凭证\"就是future。\n原理\nFutureTask就是Future的基本实现,下面我们就从代码分析一下实现的原理。\n源码基本JDK1.8。\nFuture接口\n我们先看看Future的定义,即你拿到这个\"凭证\"之后你能干点什么。\npublic interface Future\u003cV\u003e {\n\n //取消这次任务\n boolean cancel(boolean mayInterruptIfRunning);\n //看看是否取消了\n boolean isCancelled();\n //看看是否完成了\n boolean isDone();\n //获取结果\n V get() throws InterruptedException, ExecutionException;\n //时间内获取结果,超时则抛异常\n V get(long timeout, TimeUnit unit)\n throws InterruptedException, ExecutionException, TimeoutException;\n}\n使用\n如果没用过的,这里简单演示一下Future怎么使用,大家有个感性认识。\nprivate static ExecutorService threadPool = Executors.newCachedThreadPool();\n\n public static void main(String[] args) throws Exception {\n //通过线程池提交任务,并返回一个future\n Future\u003cString\u003e future = threadPool.submit(new AsyncTask());\n //通过future获取结果。get之前一直阻塞直到有结果返回。\n String result = future.get();\n System.out.println(result);\n }\n\n public class AsyncTask implements Callable\u003cString\u003e {\n\n @Override\n public String call() throws Exception {\n TimeUnit.SECONDS.sleep(5);\n return \"ok\";\n }\n }\n继承关系\n?\nFutureTask是一个RunnableFuture,这个很好理解,就是Runnable+Future了。\n提交任务\n从任务的提交入手分析源码。\nAbstractExecutorService的submit方法。\npublic \u003cT\u003e Future\u003cT\u003e submit(Callable\u003cT\u003e task) {\n if (task == null) throw new NullPointerException();\n //这里封装了一下callable变成一个RunnableFuture\n RunnableFuture\u003cT\u003e ftask = newTaskFor(task);\n //注意线程池执行的是RunnableFuture,因为这个Future继承Runnable,所以它是可执行的。\n execute(ftask);\n //返回future\n return ftask;\n }\nsubmit方法也是支持Runnable的。ExecutorService内部会把Runnable转成Callable,只不过Runnable的返回值为null。\nFutureTask的属性/状态\n先看下FutureTask的一些内部属性,才好了解它是怎么运行的。\n//重要属性\"状态\"state定义为volatile,为了在高并发下能够获取到最新的值\nprivate volatile int state;\n //为state定义了7个状态,看名字都挺好了解的。\n private static final int NEW = 0;\n private static final int COMPLETING = 1;\n //正常结束\n private static final int NORMAL = 2;\n private static final int EXCEPTIONAL = 3;\n private static final int CANCELLED = 4;\n private static final int INTERRUPTING = 5;\n private static final int INTERRUPTED = 6;\n\n //状态之间的转换\n * Possible state transitions:\n * NEW -\u003e COMPLETING -\u003e NORMAL\n * NEW -\u003e COMPLETING -\u003e EXCEPTIONAL\n * NEW -\u003e CANCELLED\n * NEW -\u003e INTERRUPTING -\u003e INTERRUPTED\n */\n\n //用户提交的真正任务\n private Callable\u003cV\u003e callable;\n //返回结果\n private Object outcome; // non-volatile, protected by state reads/writes\n //记录跑任务的那个线程,只有一个在运行。取消时可以中断这个线程的行为。\n private volatile Thread runner;\n /** Treiber stack of waiting threads */\n //这个属性比较重要,后面讲的比较多。记录WaitNode链表的头部,volatile。WaitNode链表是等待结果的线程集合,即这个任务还没跑完时,但同时有很多持有这个future的线程调用了get方法获取结果。\n private volatile WaitNode waiters;\nrun方法\n当这个RunnableFuture提交到线程池后,它做了什么。\npublic void run() {\n //为了防止future重复运行,需要判断是NEW状态。\n //同时记录runner属性\n //这里UNSAFE的CAS操作在JUC里用的比较多,不展开了(我的原则是,不是这个话题的内容不过多展开,保持专注和精简。)\n if (state != NEW ||\n !UNSAFE.compareAndSwapObject(this, runnerOffset,\n null, Thread.currentThread()))\n return;\n try {\n Callable\u003cV\u003e c = callable;\n if (c != null \u0026\u0026 state == NEW) {\n V result;\n boolean ran;\n try {\n //执行用户的callable\n result = c.call();\n ran = true;\n } catch (Throwable ex) {\n result = null;\n ran = false;\n //如果callable运行异常了,这里会把这个异常吃掉,然后调用setException方法\n setException(ex);\n }\n if (ran)\n //正常结束就是设置结果\n set(result);\n }\n } finally {\n // runner must be non-null until state is settled to\n // prevent concurrent calls to run()\n runner = null;\n // state must be re-read after nulling runner to prevent\n // leaked interrupts\n int s = state;\n if (s \u003e= INTERRUPTING)\n handlePossibleCancellationInterrupt(s);\n }\n }\n值得注意的是,如果原来的callable任务运行异常了,那么在run方法中会直接catch掉,然后在get的时候才抛出来。这么也是为了做错误隔离,为了callable的异常不会影响到future的运行。\nsetException方法\nprotected void setException(Throwable t) {\n if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {\n //把结果设为异常\n outcome = t;\n //更新状态为EXCEPTIONAL\n UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state\n //finishCompletion作为一个结束动作\n finishCompletion();\n }\n }\nset方法\nprotected void set(V v) {\n if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {\n //设置结果\n outcome = v;\n //更新状态为NORMAL\n UNSAFE.putOrderedInt(this, stateOffset, NORMAL);\n //同样调用了finishCompletion方法\n finishCompletion();\n }\n }\nsetException方法和set方法都是protected,不能随意调用,不过子类可以改变它的行为。\nCOMPLETING状态?\n在上面说到的7个状态中有一个COMPLETING的状态,它表示新建NEW和正常结束NORMAL或异常结束EXCEPTIONAL中间的这么一个状态,在set和setException用到了,会先把NEW状态更新为COMPLETING,再把COMPLETING更新为对应的结果状态。\n刚开始我认为这个状态是没必要的。因为这个FutureTask只会有一个线程在运行它,不存在竞争,而且看代码也知道,作者没对竞争失败做处理,那么set和setException的CAS操作是肯定会成功的,所以我觉得把COMPLETING变成NEW也是可以的。但是细想如果直接把\nUNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)\n变成\nUNSAFE.compareAndSwapInt(this, stateOffset, NEW, NORMAL)\n但是后面还有一步赋值操作。\noutcome = v\n并发下,这时如果有其他线程在CAS后想获取结果,就返回null了。\nfinishCompletion方法\n//如果这个future正常结束,异常结束,被取消了,都会调用这个方法。\nprivate void finishCompletion() {\n // assert state \u003e COMPLETING;\n //这里会不停的拿头部节点做遍历,直到头部节点为null。这是为了防止在并发下有新的节点新插入进来。\n for (WaitNode q; (q = waiters) != null;) {\n //CAS把WaitNode链表的头部设为null。\n if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {\n for (;;) {\n Thread t = q.thread;\n if (t != null) {\n q.thread = null;\n //唤醒WaitNode的线程,唤醒的线程继续在awaitDone方法里做循环。\n LockSupport.unpark(t);\n }\n WaitNode next = q.next;\n //直到next为null,完成链表的遍历\n if (next == null)\n break;\n q.next = null; // unlink to help gc\n q = next;\n }\n break;\n }\n }\n //这个done方法是预留方法,子类可以继承它来做点别的。\n done();\n\n callable = null; // to reduce footprint\n }\nget方法\nget方法是重点。\n因为作者设计FutureTask是支持高并发的,而且用了Lock-Free无锁算法,所以阅读起来会比较费劲。\npublic V get() throws InterruptedException, ExecutionException {\n int s = state;\n if (s \u003c= COMPLETING)\n s = awaitDone(false, 0L);\n return report(s);\n }\nWaitNode链表\n继续看下去之前,先看看WaitNode的定义。\n很简单,只有一个Thread和next指针。Thread就是指当前需要获取future结果的那个线程。WaitNode通过next指针形成一条链表。\nstatic final class WaitNode {\n volatile Thread thread;\n volatile WaitNode next;\n WaitNode() { thread = Thread.currentThread(); }\n }\n这是在Lock-Free中常见的数据结构,看上去是不是有点像AQS呢?\n/*\n * Revision notes: This differs from previous versions of this\n * class that relied on AbstractQueuedSynchronizer, mainly to\n * avoid surprising users about retaining interrupt status during\n * cancellation races. Sync control in the current design relies\n * on a \"state\" field updated via CAS to track completion, along\n * with a simple Treiber stack to hold waiting threads.\n *\n * Style note: As usual, we bypass overhead of using\n * AtomicXFieldUpdaters and instead directly use Unsafe intrinsics.\n */\n实际上,官方也说了,之前版本的实现是用了AQS的,原因是...(这个原因我不是很懂是啥意思),现在改为Treiber stack算法了。\nawaitDone方法\nprivate int awaitDone(boolean timed, long nanos)\n throws InterruptedException {\n final long deadline = timed ? System.nanoTime() + nanos : 0L;\n WaitNode q = null;\n boolean queued = false;\n //死循环直到s \u003e COMPLETING或者超时,当然这个不是真的死循环,大部分情况下线程是会挂起的。\n for (;;) {\n //如果线程是被中断了,则从链表移除当前节点,然后抛异常\n if (Thread.interrupted()) {\n removeWaiter(q);\n throw new InterruptedException();\n }\n\n int s = state;\n //从上面7个状态看出,当s \u003e COMPLETING都是结束的状态,要不正常结束,异常,取消等。可见合理的状态值设计带来的方便。\n if (s \u003e COMPLETING) {\n if (q != null)\n q.thread = null;\n return s;\n }\n //这里就是为了防止上面我说的,结果赋值时并发下其他线程获取不到值的情况,所以让这个线程yield一下,再做一次循环,说不定下次就是s \u003e COMPLETING呢。\n else if (s == COMPLETING) // cannot time out yet\n Thread.yield();\n else if (q == null)\n //新建一个WaitNode,准备进链表\n q = new WaitNode();\n else if (!queued)\n //CAS把WaitNode节点插入到链表的头部,如果失败则下次继续插入\n queued = UNSAFE.compareAndSwapObject(this, waitersOffset,\n q.next = waiters, q);\n //如果get方法设置了超时时间,则会进入这个分支,如果超时了,也会返回state。还没超时则挂起,挂起的时间为时间差。\n else if (timed) {\n nanos = deadline - System.nanoTime();\n if (nanos \u003c= 0L) {\n //超时需要从链表移除当前节点\n removeWaiter(q);\n return state;\n }\n LockSupport.parkNanos(this, nanos);\n }\n //注意这里,是最后的步骤,即当s \u003c COMPLETING,已经插入链表了,不是超时的情况\n else\n LockSupport.park(this);\n }\n }\nawaitDone方法返回的是state状态的值。\n要注意if else执行的顺序,先是判断中断状态,其次判断state的完成状态,再是新建节点,然后插入,最后才是挂起。用for循环去尝试当CAS失败的情况。\n插入节点的只有这个方法,所以我们可以知道,链表的结构如下:\n?\nremoveWaiter方法的作用是当中断或超时时移除当前的WaitNode。这个方法有点不好理解。\nprivate void removeWaiter(WaitNode node) {\n if (node != null) {\n node.thread = null;\n retry:\n for (;;) { // restart on removeWaiter race\n for (WaitNode pred = null, q = waiters, s; q != null; q = s) {\n s = q.next;\n if (q.thread != null)\n pred = q;\n else if (pred != null) {\n pred.next = s;\n if (pred.thread == null) // check for race\n continue retry;\n }\n else if (!UNSAFE.compareAndSwapObject(this, waitersOffset,\n q, s))\n continue retry;\n }\n break;\n }\n }\n }\n我们画个图,分情况来理解一下\n?\n如果q.thread != null\n因为进来时已经直接把node.thread = null,说明q已经不是当前的node,q是其他线程插入进来的node,这时需要把s,q,pred继续往左移动。\n如果q.thread == null \u0026\u0026 pred != null\n这时可以把pred的next指向s了,即删除了q。但是如果pred.thread == null,说明pred的线程也把它自己的节点删除了(删除节点的情况除了removeWaiter,还有正常获取结果后也会),所以pred已经没用了,需要重新来找到新的pred。\n如果q.thread == null \u0026\u0026 pred == null\n说明前面的节点都被删除了,已经没用了,把s直接置为头部。\nreport方法\n比较简单了\nprivate V report(int s) throws ExecutionException {\n Object x = outcome;\n if (s == NORMAL)\n //task正常执行就返回结果\n return (V)x;\n if (s \u003e= CANCELLED)\n //取消则抛异常\n throw new CancellationException();\n //否则抛出task运行的异常\n throw new ExecutionException((Throwable)x);\n }\ncancel方法\n//mayInterruptIfRunning参数,取消的同时可以中断runner线程的运行。\npublic boolean cancel(boolean mayInterruptIfRunning) {\n //状态更新为INTERRUPTING或CANCELLED\n if (!(state == NEW \u0026\u0026\n UNSAFE.compareAndSwapInt(this, stateOffset, NEW,\n mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))\n return false;\n try { // in case call to interrupt throws exception\n //中断\n if (mayInterruptIfRunning) {\n try {\n Thread t = runner;\n if (t != null)\n //调用线程的interrupt方法来中断线程\n t.interrupt();\n } finally { // final state\n UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);\n }\n }\n } finally {\n //取消也要把watiers清空掉\n finishCompletion();\n }\n return true;\n }\n缺点\nFutureTask有明显的下面两个缺点:\n重复提交\n并发会有重复提交的可能,虽然在内部有对状态NEW的判断,但那只是针对那个FutureTask实例的,我们看到,在submit方法中每次提交任务都会new 一个\nFutureTask出来的。\n不过现在已经有一个解决方案Memoizer\n其实很简单,就是用一个key来记录这次的Future,然后放在一个Map里,下次用到时再从Map里取出来。\n批量任务\nFuture每次只能提交一个任务,而且获取结果之前会一直阻塞,这点也是很不友好的。\n综上,FutureTask只是提供了一个基本的功能实现,远远不能满足要求高的我们,guava的ListenableFuture和JDK1.8的CompletableFuture都是对Future的增强,前者提供监听器处理结果,后者更加强大,提供链式调用,同步、异步结果返回不同的组合方式来帮助你处理复杂的业务场景。\n总结\n源码部分已经介绍的7788了。因为采用了无锁算法,所以实现起来看上去代码比较复杂,看代码时要意识到这个,多想想在高并发下链表会出现怎样的情况,我没有把所有可能出现的情况都罗列出来,所以要靠读者自己多思考。\n总的来说,Future通过循环判断state状态,挂起、唤醒线程的操作,来实现异步阻塞,通过一个WaitNode链表来处理并发的情况。","showReadNum":1282,"sourceDetail":null,"sourceType":99,"status":2,"summary":"Future是一种异步计算的模式,本文带你理解一下什么是Future,以及基本的FutureTask的实现原理。","tagIds":[10663,10802,10620,10200],"title":"理解Future及FutureTask的实现","uid":1444933,"updateTime":1597632104,"userSummary":"","userUpdateTime":0},"authorInfo":{"articleNum":0,"avatarUrl":"https://ask.qcloudimg.com/avatar/1444933/q9xecryc4m.png","company":"","introduce":"Java码农一个","isProfessionVerified":0,"nickname":"Erwin","privilege":1,"title":"","uid":1444933},"authorType":{"isBlogMoveAuthor":0,"isCoCreator":0,"isInternalAuthor":0,"isOriginalAuthor":0},"classify":[{"id":4,"name":"后端"}],"columnInfo":{"columnAvatar":"https://imgcache.qq.com/qcloud/developer/images/release/column-icons/19.png","columnDesc":"","columnId":3608,"columnName":"啸天\"s blog","createTime":1526527388,"createUid":1444933,"memberNum":1,"showArticleNum":147,"showConcernNum":44},"columnList":[{"columnAvatar":"https://imgcache.qq.com/qcloud/developer/images/release/column-icons/19.png","columnDesc":"","columnId":3608,"columnName":"啸天\"s blog","createTime":1526527388,"createUid":1444933,"memberNum":1,"showArticleNum":147,"showConcernNum":44}],"editTime":0,"isTencent":false,"longtailTags":[],"publishTime":1597632104,"sourceDetail":{"blogType":2,"blogUrl":"https://xtboke.cn/","channelSource":"xtboke","originalTime":"2020-08-14","sourceAuthor":"","sourceLink":"https://xtboke.cn/jsjc/653.html","wechatNickName":"","wechatUserName":""},"tags":[{"categoryId":99,"createTime":"2018-09-06T18:30:02+08:00","groupId":0,"groupName":"","tagId":10663,"tagName":"编程算法"},{"categoryId":3,"createTime":"2018-09-06T18:31:36+08:00","groupId":10551,"groupName":"大数据技术","tagId":10802,"tagName":"数据分析"},{"categoryId":3,"createTime":"2018-07-20T18:32:46+08:00","groupId":10136,"groupName":"服务器技术","tagId":10620,"tagName":"http"},{"categoryId":3,"createTime":"2018-05-11T12:09:32+08:00","groupId":10121,"groupName":"前端开发","tagId":10200,"tagName":"node.js"}],"textLink":[{"ext":null,"id":2102,"link":"https://cloud.tencent.com/product/tcap","sources":[1],"text":"代码分析"},{"ext":{"categoryId":1033,"categoryName":"通用技术 - 游戏开发","desc":"数据结构是计算机科学中研究数据组织和存储方式的一门学科,主要研究各种数据对象在计算机内存中的组织方式和存储结构,以及对这些数据对象进行操作的算法和方法。在计算机程序设计中,数据结构是指数据元素之间的关系和操作方式的抽象描述,是程序设计中最基本的概念之一。","kpCount":7,"name":"数据结构","pCategoryId":1002,"termId":1914},"id":3612,"link":"https://cloud.tencent.com/developer/techpedia/1914","sources":[2],"text":"数据结构"}]},"#url:\"/api/tag/products\",params:#tagIds:@10663,10802,10620,10200,,objectType:1,objectId:1680378,,":[{"adActivity":{"id":5738,"lightSpotLabel":"HOT","pageUrl":"https://cloud.tencent.com/act/pro/double11-2024","priority":1,"startTime":"2023/12/12 17:58:46","title":"11.11 上云拼团GO"},"cnName":"腾讯云代码分析","desc":"腾讯云代码分析(内部代号CodeDog)是集众多代码分析工具的云原生、分布式、高性能的代码综合分析跟踪管理平台,其主要功能是持续跟踪分析代码,观测项目代码质量,助力维护团队卓越代码文化。","docURL":"https://cloud.tencent.com/document/product/1460","hasActivity":false,"icon":"https://main.qcloudimg.com/image/product/2742/32_32/blue.svg","introURL":"https://cloud.tencent.com/product/tcap","name":"tcap","productId":11228,"shortDesc":"云原生、分布式、高性能的代码综合分析平台,保障项目敏捷迭代下的代码质量","tagId":11346}]},"tdk":{"title":"理解Future及FutureTask的实现-腾讯云开发者社区-腾讯云","keywords":"编程算法,数据分析,http,node.js","description":"Future是一种异步计算的模式,本文带你理解一下什么是Future,以及基本的FutureTask的实现原理。"},"meta":{"subject":"其他-空类-编程算法,通用技术-大数据技术-数据分析,通用技术-服务器技术-http,通用技术-前端开发-node.js","subjectTime":"2020-08-17 10:41:44","articleSource":"B","magicSource":"N","authorType":"","productSlug":"tcap"},"link":{"canonical":"https://cloud.tencent.com/developer/article/1680378"},"cssName":["Article","DraftMaster","Player"],"rbConfigKeys":["groupQRKeywords"],"pvId":"uPUIjE-rSXEfDBRMF3e2N","clientIp":"8.222.208.146","globalAnnounce":{"announceId":29,"content":"发文进行双十一晒单,聊省钱攻略,开箱云产品,最高赢万元奖励。点击查看活动详情:\u003ca href=\"https://cloud.tencent.com/developer/article/2462518\" target=\"_blank\"\u003ehttps://cloud.tencent.com/developer/article/2462518\u003c/a\u003e\u003cbr/\u003e \n \u003cimg src=\"https://qcloudimg.tencent-cloud.cn/raw/9f72dee064adec96fefa6f314527b6fe.jpg\"/\u003e","title":" 摇人!全网寻技术圈双十一课代表!"},"rbConfig":{"groupQRKeywords":{"AI":{"keywords":[],"img":"https://qcloudimg.tencent-cloud.cn/raw/89b22f53dc3d4e0516d0a4f74ab01a30.png"}},"versionUpdateTipList":"","navList":[{"text":"学习","menuList":[{"iconName":"article","title":"文章","desc":"技术干货聚集地","href":"/developer/column?from=19154"},{"iconName":"ask","title":"问答","desc":"技术问题讨论区","href":"/developer/ask?from=19155"},{"iconName":"video","title":"视频","desc":"技术视频记录区","href":"/developer/video?from=19156"},{"iconName":"learn","title":"学习中心","desc":"一站式学习平台","href":"/developer/learning"},{"iconName":"lab","title":"腾讯云实验室","desc":"体验腾讯云产品功能","href":"/lab/labslist?from=20154\u0026from_column=20154\u0026channel=c1004\u0026sceneCode=dev"}]},{"text":"活动","menuList":[{"iconName":"living","title":"直播","desc":"技术大咖面对面","href":"/developer/salon?from=19161"},{"iconName":"competition","title":"竞赛","desc":"秀出你的技术影响力","href":"/developer/competition?from=19162"}]},{"text":"专区","menuList":[{"iconName":"code","title":"CODING DevOps专区","desc":"云原生开发技术实践交流","href":"/developer/zone/codingdevops?from=19163"},{"iconName":"cloudstudio","title":"Cloud Studio专区","desc":"云端IDE开发者平台","href":"/developer/zone/cloudstudio?from=19165"},{"iconName":"cloudnative","title":"腾讯云原生专区","desc":"助力业务降本增效","href":"/developer/zone/cloudnative?from=19164"},{"iconName":"https://qccommunity.qcloudimg.com/community/image/ipass.svg","title":"腾讯轻联专区 ","desc":"新一代应用与数据集成平台","href":"/developer/zone/ipaas"},{"iconName":"https://qcloudimg.tencent-cloud.cn/raw/1deae15bfe2dcdd1036f601852df7dd2.svg","title":"腾讯云数据库专区","desc":"数据智能管理专家","href":"/developer/zone/tencentdb"},{"iconName":"https://qcloudimg.tencent-cloud.cn/raw/cb0703ff9de6b664413f4ed7d31a9224.svg","title":"腾讯云大数据专区","desc":"打造专业、易用、可信赖的大数据产品","href":"/developer/zone/bigdata"},{"iconName":"https://qcloudimg.tencent-cloud.cn/raw/1d60f881ef280ea992e2e4b6490d974b.svg","title":"腾讯云TCE专区","desc":"私有化云解决方案","href":"/developer/zone/tce"},{"iconName":"https://qccommunity.qcloudimg.com/community/image/cos.svg","title":"腾讯云存储专区","desc":"安全稳定的海量分布式存储服务","href":"/developer/zone/cos"},{"iconName":"https://qccommunity.qcloudimg.com/community/image/andon.svg","title":"腾讯云安灯专区","desc":"助力企业构建IT服务管理体系","href":"/developer/zone/tcandon"},{"iconName":"https://qccommunity.qcloudimg.com/community/image/sale.svg","title":"腾讯云运维技术沙龙","desc":"聚焦运维技术与云上治理","href":"/developer/zone/tcdevopssalon"},{"iconName":"https://qccommunity.qcloudimg.com/community/image/audio.svg","title":"腾讯云音视频","desc":"提供坚实的数字化助力","href":"/developer/zone/mediaservices"},{"iconName":"https://qccommunity.qcloudimg.com/icons/tencentcloudsmartadvisor.svg","title":"腾讯云顾问","desc":"实现便捷、灵活的一站式云上治理","href":"https://cloud.tencent.com/developer/zone/tencentcloudsmartadvisor"},{"iconName":"https://qccommunity.qcloudimg.com/icons/tencenthunyuan.svg","title":"腾讯混元","desc":"具备强大的中文创作、逻辑推理、任务执行能力","href":"https://cloud.tencent.com/developer/zone/tencenthunyuan"},{"iconName":"https://qccommunity.qcloudimg.com/community/image/ai.svg","title":"腾讯云智能","desc":"数实融合,云上智能","href":"https://cloud.tencent.com/developer/zone/ai"},{"iconName":"https://qccommunity.qcloudimg.com/community/image/Dnspod.svg","title":"dnspod","desc":"专业的智能DNS解析和域名托管服","href":"https://cloud.tencent.com/developer/zone/dnspod"},{"iconName":"https://qccommunity.qcloudimg.com/community/image/lighthouse.svg","title":"轻量应用服务器","desc":"新一代开箱即用、面向轻量应用场景的云服务器","href":"https://cloud.tencent.com/developer/zone/lighthouse"},{"iconName":"https://qccommunity.qcloudimg.com/community/image/HAi.svg","title":"高性能应用服务","desc":"提供即插即用的高性能云服务","href":"https://cloud.tencent.com/developer/zone/hai"},{"iconName":"https://qccommunity.qcloudimg.com/community/image/blockchain.svg","title":"腾讯云区块链","desc":"云链聚未来,协同无边界","href":"https://cloud.tencent.com/developer/zone/tencentcouldbockchain"},{"iconName":"https://qccommunity.qcloudimg.com/community/image/OpencloudOS.svg","title":"OpenCloudOS","desc":"开源中立的国产操作系统社区","href":"https://cloud.tencent.com/developer/zone/opencloudos"},{"iconName":"https://cloudcache.tencent-cloud.com/qcloud/ui/static/static_source_business/b3e1b483-be77-4e08-827f-ef0e5cda26cf.svg","title":"边缘安全加速平台EO","desc":"下一代CDN—EdgeOne,不止加速","href":"https://cloud.tencent.com/developer/zone/tencentcloudedgeone"}]},{"text":"工具","menuList":[{"iconName":"https://qccommunity.qcloudimg.com/icons/ai-assistant.svg","title":"腾讯云AI代码助手","desc":"辅助编码工具,使研发提效增质","href":"https://cloud.tencent.com/product/acc?from=22178"},{"iconName":"coding","title":"CODING DevOps","desc":"一站式软件研发管理平台","href":"/product/coding?from=20154\u0026from_column=20154"},{"iconName":"studio","title":"Cloud Studio","desc":"随时随地在线协作开发","href":"/product/cloudstudio?from=20154\u0026from_column=20154"},{"iconName":"sdk","title":"SDK中心","desc":"开发者语言与SDK","href":"/document/sdk?from=20154\u0026from_column=20154"},{"iconName":"api","title":"API中心","desc":"API 助力快捷使用云产品","href":"/document/api?from=20154\u0026from_column=20154"},{"iconName":"tool","title":"命令行工具","desc":"可快速调用管理云资源","href":"/document/product/440/6176?from=20154\u0026from_column=20154"}]}],"activity-popup":{"mImgUrl":"https://qccommunity.qcloudimg.com/mp/images/11-11mobile.jpg","imgUrl":"https://qccommunity.qcloudimg.com/mp/images/11-11pc.jpg","beginTime":"2024/10/24 00:00:00","endTime":"2024/10/31 23:59:59"},"header-advertisement":{"imageUrl":"https://qccommunity.qcloudimg.com/image/2024-11-01-18-15.png","link":"https://cloud.tencent.com/act/pro/double11-2024?from=22374\u0026from_column=22374#miaosha"}},"isBot":false,"session":{"isLogined":false,"isQCloudLogined":false,"isQCommunityLogined":false,"isDifferentUin":false}}},"page":"/article/[articleId]","query":{"articleId":"1680378"},"buildId":"A33mNyh0oM2Hz_SodWz7T","assetPrefix":"https://qccommunity.qcloudimg.com/community","isFallback":false,"gssp":true,"appGip":true,"scriptLoader":[]}</script></body></html>