You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

671 lines
228 KiB

<!doctypehtml><html lang=zh-CN><meta charset=UTF-8><meta content=width=device-width name=viewport><meta content=#222 name=theme-color><meta content="Hexo 6.3.0" name=generator><link href=https://fonts.googleapis.com rel=preconnect><link href=https://cdnjs.cloudflare.com rel=preconnect><link href=/images/apple-touch-icon-next.png rel=apple-touch-icon sizes=180x180><link href=/images/favicon-32x32-next.png rel=icon sizes=32x32 type=image/png><link href=/images/favicon-16x16-next.png rel=icon sizes=16x16 type=image/png><link color=#222 href=/images/logo.svg rel=mask-icon><meta content=2X6S9P7CAjXjVvw8YyQR8pCu-B0oEu7O9quLgxXuWyA name=google-site-verification><meta content=dV8JGNzi0c name=baidu-site-verification><script>setTimeout(function(){var d=document.createElement("script");d.setAttribute("data-ad-client","ca-pub-7480618470784058"),d.async=!0,d.src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js",document.body.appendChild(d)},5e3),window.addEventListener?window.addEventListener("load",downloadJsAtOnload,!1):window.attachEvent?window.attachEvent("onload",downloadJsAtOnload):window.onload=downloadJsAtOnload</script><style>:root{--body-bg-color:#f5f7f9;--content-bg-color:#fff;--card-bg-color:#f5f5f5;--text-color:#555;--blockquote-color:#666;--link-color:#555;--link-hover-color:#222;--brand-color:#fff;--brand-hover-color:#fff;--table-row-odd-bg-color:#f9f9f9;--table-row-hover-bg-color:#f5f5f5;--menu-item-bg-color:#f5f5f5;--theme-color:#222;--btn-default-bg:#fff;--btn-default-color:#555;--btn-default-border-color:#555;--btn-default-hover-bg:#222;--btn-default-hover-color:#fff;--btn-default-hover-border-color:#222;--highlight-background:#f3f3f3;--highlight-foreground:#444;--highlight-gutter-background:#e1e1e1;--highlight-gutter-foreground:#555;color-scheme:light}html{line-height:1.15;-webkit-text-size-adjust:100%}details,main{display:block}pre{font-size:1em;overflow:auto;padding:10px;position:relative}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:ButtonText dotted 1px}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}.table-container,textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}summary{display:list-item}[hidden],template{display:none}::selection{background:#262a30;color:#eee}body,html{height:100%}body{margin:0;background:var(--body-bg-color);box-sizing:border-box;color:var(--text-color);font-family:Lato,'PingFang SC','Microsoft YaHei',sans-serif;font-size:1.2em;line-height:2;min-height:100%;position:relative;transition:padding .2s ease-in-out}h1,h2,h3,h4,h5,h6{font-family:Lato,'PingFang SC','Microsoft YaHei',sans-serif;font-weight:700;line-height:1.5;margin:30px 0 15px}h1{font-size:1.5em}h2{font-size:1.375em}h3{font-size:1.25em}h4{font-size:1.125em}h5{font-size:1em}h6{font-size:.875em}p{margin:0 0 20px}a{background:0 0;border-bottom:1px solid #999;color:var(--link-color);cursor:pointer;outline:0;text-decoration:none;overflow-wrap:break-word}a:hover{border-bottom-color:var(--link-hover-color);color:var(--link-hover-color)}embed,iframe,img,video{display:block;margin-left:auto;margin-right:auto;max-width:100%}hr{box-sizing:content-box;overflow:visible;background-image:repeating-linear-gradient(-45deg,#ddd,#ddd 4px,transparent 4px,transparent 8px);border:0;height:3px;margin:40px 0}blockquote{border-left:4px solid #ddd;color:var(--blockquote-color);margin:0;padding:0 15px}blockquote cite::before{content:'-';padding:0 5px}dt{font-weight:700}dd{margin:0;padding:0}table{border-collapse:collapse;border-spacing:0;font-size:.875em;margin:0 0 20px;width:100%}tbody tr:nth-of-type(odd){background:var(--table-row-odd-bg-color)}tbody tr:hover{background:var(--table-row-hover-bg-color)}caption,td,th{padding:8px}td,th{border:1px solid #ddd;border-bottom:3px solid #ddd}th{font-weight:700;padding-bottom:10px}td{border-bottom-width:1px}.btn{background:var(--btn-default-bg);border:2px solid var(--btn-default-border-color);border-radius:2px;color:var(--btn-default-color);display:inline-block;font-size:.875em;line-height:2;padding:0 20px;transition:background-color .2s ease-in-out}.btn:hover{background:var(--btn-default-hover-bg);border-color:var(--btn-default-hover-border-color);color:var(--btn-default-hover-color)}.btn+.btn{margin:0 0 8px 8px}.btn .fa-fw{text-align:left;width:1.285714285714286em}.toggle{line-height:0}.toggle .toggle-line{background:#fff;display:block;height:2px;left:0;position:relative;top:0;transition:.4s;width:100%}.toggle .toggle-line:first-child{margin-top:1px}.toggle .toggle-line:not(:first-child){margin-top:4px}.toggle.toggle-arrow :first-child{left:50%;top:2px;transform:rotate(45deg);width:50%}.toggle.toggle-arrow :last-child{left:50%;top:-2px;transform:rotate(-45deg);width:50%}.toggle.toggle-close :nth-child(2){opacity:0}.toggle.toggle-close :first-child{top:6px;transform:rotate(45deg)}.toggle.toggle-close :last-child{top:-6px;transform:rotate(-45deg)}code[class*=language-],pre[class*=language-]{color:#000;background:0 0;text-shadow:0 1px #fff;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{text-shadow:none;background:#b3d4fc}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{text-shadow:none;background:#b3d4fc}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f5f2f0}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#708090}.token.punctuation{color:#999}.token.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#905}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#690}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.class-name,.token.function{color:#dd4a68}.token.important,.token.regex,.token.variable{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}pre[class*=language-].line-numbers{position:relative;padding-left:3.8em;counter-reset:linenumber}pre[class*=language-].line-numbers>code{position:relative;white-space:inherit}.line-numbers .line-numbers-rows{position:absolute;pointer-events:none;top:0;font-size:100%;left:-3.8em;width:3em;letter-spacing:-1px;border-right:1px solid #999;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.line-numbers-rows>span{display:block;counter-increment:linenumber}.line-numbers-rows>span:before{content:counter(linenumber);color:#999;display:block;padding-right:.8em;text-align:right}.highlight:hover .copy-btn,pre:hover .copy-btn{opacity:1}figure.highlight .table-container{position:relative;border-radius:0 0 5px 5px}.copy-btn{color:#333;cursor:pointer;line-height:1.6;opacity:0;padding:2px 6px;position:absolute;transition:opacity .2s ease-in-out;color:var(--highlight-foreground);font-size:14px;right:0;top:2px}figure.highlight{border-radius:5px;box-shadow:0 10px 30px 0 rgba(0,0,0,.4);padding-top:30px;overflow:auto;position:relative}figure.highlight::before{background:#fc625d;box-shadow:20px 0 #fdbc40,40px 0 #35cd4b;left:12px;margin-top:-20px;position:absolute;border-radius:50%;content:' ';height:12px;width:12px}code,figure.highlight,kbd,pre{background:var(--highlight-background);color:var(--highlight-foreground)}figure.highlight,pre{line-height:1.6;margin:0 auto 20px}figure.highlight figcaption,pre .caption,pre figcaption{background:var(--highlight-gutter-background);color:var(--highlight-foreground);display:flow-root;font-size:.875em;line-height:1.2;padding:.5em}figure.highlight figcaption a,pre .caption a,pre figcaption a{color:var(--highlight-foreground);float:right}figure.highlight figcaption a:hover,pre .caption a:hover,pre figcaption a:hover{border-bottom-color:var(--highlight-foreground)}code,pre{font-family:consolas,Menlo,monospace,'PingFang SC','Microsoft YaHei'}code{border-radius:3px;font-size:.875em;padding:2px 4px;overflow-wrap:break-word}kbd{border:2px solid #ccc;border-radius:.2em;box-shadow:.1em .1em .2em rgba(0,0,0,.1);font-family:inherit;padding:.1em .3em;white-space:nowrap}figure.highlight pre{border:0;margin:0;padding:10px 0}figure.highlight table{border:0;margin:0;width:auto}figure.highlight td{border:0;padding:0}figure.highlight .gutter{-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;user-select:none}figure.highlight .gutter pre{background:var(--highlight-gutter-background);color:var(--highlight-gutter-foreground);padding-left:10px;padding-right:10px;text-align:right}figure.highlight .code pre{padding-left:10px;width:100%}figure.highlight .marked{background:rgba(0,0,0,.3)}pre .caption,pre figcaption{margin-bottom:10px}.gist table{width:auto}.gist table td{border:0}pre code{background:0 0;padding:0;text-shadow:none}.blockquote-center{border-left:0;margin:40px 0;padding:0;position:relative;text-align:center}.blockquote-center::after,.blockquote-center::before{left:0;line-height:1;opacity:.6;position:absolute;width:100%}.blockquote-center::before{border-top:1px solid #ccc;text-align:left;top:-20px;content:'\f10d';font-family:'Font Awesome 6 Free';font-weight:900}.blockquote-center::after{border-bottom:1px solid #ccc;bottom:-20px;text-align:right;content:'\f10e';font-family:'Font Awesome 6 Free';font-weight:900}.blockquote-center div,.blockquote-center p{text-align:center}.group-picture{margin-bottom:20px}.group-picture .group-picture-row{display:flex;gap:3px;margin-bottom:3px}.group-picture .group-picture-column{flex:1}.group-picture .group-picture-column img{height:100%;margin:0;object-fit:cover;width:100%}.post-body .label{color:#555;padding:0 2px}.post-body .label.default{background:#f0f0f0}.post-body .label.primary{background:#efe6f7}.post-body .label.info{background:#e5f2f8}.post-body .label.success{background:#e7f4e9}.post-body .label.warning{background:#fcf6e1}.post-body .label.danger{background:#fae8eb}.post-body .link-grid{display:grid;grid-gap:1.5rem;gap:1.5rem;grid-template-columns:1fr 1fr;margin-bottom:20px;padding:1rem}.post-body .link-grid .link-grid-container{border:solid #ddd;box-shadow:1rem 1rem .5rem rgba(0,0,0,.5);min-height:5rem;min-width:0;padding:.5rem;position:relative;transition:background .3s}.post-body .link-grid .link-grid-container:hover{animation:.5s next-shake;background:var(--card-bg-color)}.post-body .link-grid .link-grid-container:active{box-shadow:.5rem .5rem .25rem rgba(0,0,0,.5);transform:translate(.2rem,.2rem)}.post-body .link-grid .link-grid-container .link-grid-image{border:1px solid #ddd;border-radius:50%;box-sizing:border-box;height:5rem;padding:3px;position:absolute;width:5rem}.post-body .link-grid .link-grid-container p{margin:0 1rem 0 6rem}.post-body .link-grid .link-grid-container p:first-of-type{font-size:1.2em}.post-body .link-grid .link-grid-container p:last-of-type{font-size:.8em;line-height:1.3rem;opacity:.7}.post-body .link-grid .link-grid-container a{border:0;height:100%;left:0;position:absolute;top:0;width:100%}@keyframes next-shake{0%{transform:translate(1pt,1pt) rotate(0)}10%{transform:translate(-1pt,-2pt) rotate(-1deg)}20%{transform:translate(-3pt,0) rotate(1deg)}30%{transform:translate(3pt,2pt) rotate(0)}40%{transform:translate(1pt,-1pt) rotate(1deg)}50%{transform:translate(-1pt,2pt) rotate(-1deg)}60%{transform:translate(-3pt,1pt) rotate(0)}70%{transform:translate(3pt,1pt) rotate(-1deg)}80%{transform:translate(-1pt,-1pt) rotate(1deg)}90%{transform:translate(1pt,2pt) rotate(0)}100%{transform:translate(1pt,-2pt) rotate(-1deg)}}.post-body .note{border-radius:3px;margin-bottom:20px;padding:1em;position:relative;border:1px solid #eee;border-left-width:5px}.post-body .note summary{cursor:pointer;outline:0}.post-body .note summary p{display:inline}.post-body .note h2,.post-body .note h3,.post-body .note h4,.post-body .note h5,.post-body .note h6{border-bottom:initial;margin:0;padding-top:0}.post-body .note :first-child{margin-top:0}.post-body .note :last-child{margin-bottom:0}.post-body .note.default{border-left-color:#777}.post-body .note.default h2,.post-body .note.default h3,.post-body .note.default h4,.post-body .note.default h5,.post-body .note.default h6{color:#777}.post-body .note.primary{border-left-color:#6f42c1}.post-body .note.primary h2,.post-body .note.primary h3,.post-body .note.primary h4,.post-body .note.primary h5,.post-body .note.primary h6{color:#6f42c1}.post-body .note.info{border-left-color:#428bca}.post-body .note.info h2,.post-body .note.info h3,.post-body .note.info h4,.post-body .note.info h5,.post-body .note.info h6{color:#428bca}.post-body .note.success{border-left-color:#5cb85c}.post-body .note.success h2,.post-body .note.success h3,.post-body .note.success h4,.post-body .note.success h5,.post-body .note.success h6{color:#5cb85c}.post-body .note.warning{border-left-color:#f0ad4e}.post-body .note.warning h2,.post-body .note.warning h3,.post-body .note.warning h4,.post-body .note.warning h5,.post-body .note.warning h6{color:#f0ad4e}.post-body .note.danger{border-left-color:#d9534f}.post-body .note.danger h2,.post-body .note.danger h3,.post-body .note.danger h4,.post-body .note.danger h5,.post-body .note.danger h6{color:#d9534f}.post-body .tabs{margin-bottom:20px}.post-body .tabs,.tabs-comment{padding-top:10px}.post-body .tabs ul.nav-tabs,.tabs-comment ul.nav-tabs{background:var(--content-bg-color);display:flex;display:flex;flex-wrap:wrap;justify-content:center;margin:0;padding:0;position:-webkit-sticky;position:sticky;top:0;z-index:5}.post-body .tabs ul.nav-tabs li.tab,.tabs-comment ul.nav-tabs li.tab{border-bottom:1px solid #ddd;border-left:1px solid transparent;border-right:1px solid transparent;border-radius:0;border-top:3px solid transparent;flex-grow:1;list-style-type:none}@media (max-width:413px){.post-body .tabs ul.nav-tabs,.tabs-comment ul.nav-tabs{display:block;margin-bottom:5px}.post-body .tabs ul.nav-tabs li.tab,.tabs-comment ul.nav-tabs li.tab{border-bottom:1px solid transparent;border-left:3px solid transparent;border-right:1px solid transparent;border-top:1px solid transparent;border-radius:0}}.post-body .tabs ul.nav-tabs li.tab a,.tabs-comment ul.nav-tabs li.tab a{border-bottom:initial;display:block;line-height:1.8;padding:.25em .75em;text-align:center;transition:.2s ease-out}.post-body .tabs ul.nav-tabs li.tab a i,.tabs-comment ul.nav-tabs li.tab a i{width:1.285714285714286em}.post-body .tabs ul.nav-tabs li.tab.active,.tabs-comment ul.nav-tabs li.tab.active{border-color:#fc6423 #ddd transparent}@media (max-width:413px){.post-body .tabs ul.nav-tabs li.tab.active,.tabs-comment ul.nav-tabs li.tab.active{border-color:#ddd #ddd #ddd #fc6423}}.post-body .tabs ul.nav-tabs li.tab.active a,.tabs-comment ul.nav-tabs li.tab.active a{cursor:default}.post-body .tabs .tab-content,.tabs-comment .tab-content{border:1px solid #ddd;border-radius:0;border-top-color:transparent}@media (max-width:413px){.post-body .tabs .tab-content,.tabs-comment .tab-content{border-radius:0;border-top-color:#ddd}}.post-body .tabs .tab-content .tab-pane,.tabs-comment .tab-content .tab-pane{padding:20px 20px 0}.post-body .tabs .tab-content .tab-pane:not(.active),.tabs-comment .tab-content .tab-pane:not(.active){display:none}.pagination .next,.pagination .page-number,.pagination .prev,.pagination .space{display:inline-block;margin:-1px 10px 0;padding:0 10px}.algolia-pagination .current .page-number,.pagination .page-number.current{background:#ccc;border-color:#ccc;color:var(--content-bg-color)}.pagination{border-top:1px solid #eee;margin:120px 0 0;text-align:center}.pagination .next,.pagination .page-number,.pagination .prev{border-bottom:0;border-top:1px solid #eee;transition:border-color .2s ease-in-out}.pagination .next:hover,.pagination .page-number:hover,.pagination .prev:hover{border-top-color:var(--link-hover-color)}@media (max-width:767px){.post-body .link-grid{grid-template-columns:1fr}.pagination .next,.pagination .page-number,.pagination .prev,.pagination .space{margin:0 5px}.pagination{border-top:0}.pagination .next,.pagination .page-number,.pagination .prev{border-bottom:1px solid #eee;border-top:0}.pagination .next:hover,.pagination .page-number:hover,.pagination .prev:hover{border-bottom-color:var(--link-hover-color)}.site-meta{text-align:center}}.pagination .space{margin:0;padding:0}.comments{margin-top:60px;overflow:hidden}.comment-button-group{display:flex;display:flex;flex-wrap:wrap;justify-content:center;justify-content:center;margin:1em 0}.comment-button-group .comment-button{margin:.1em .2em}.comment-button-group .comment-button.active{background:var(--btn-default-hover-bg);border-color:var(--btn-default-hover-border-color);color:var(--btn-default-hover-color)}.comment-position{display:none}.comment-position.active{display:block}.tabs-comment{margin-top:4em;padding-top:0}.tabs-comment .comments{margin-top:0;padding-top:0}.headband{background:var(--theme-color);height:3px}@media (max-width:991px){.headband{display:none}}.site-brand-container{display:flex;flex-shrink:0;padding:0 10px}.use-motion .column,.use-motion .site-brand-container .toggle{opacity:0}.site-meta{flex-grow:1;text-align:center}.custom-logo-image{margin-top:20px}@media (max-width:991px){.custom-logo-image{display:none}}.brand{border-bottom:0;color:var(--brand-color);display:inline-block;padding:0}.brand:hover{color:var(--brand-hover-color)}.site-title{font-family:Lato,'PingFang SC','Microsoft YaHei',sans-serif;font-size:1.375em;font-weight:400;line-height:1.5;margin:0}.site-subtitle{color:#ddd;font-size:.8125em;margin:10px 10px 0}.use-motion .custom-logo-image,.use-motion .site-subtitle,.use-motion .site-title{opacity:0;position:relative;top:-10px}.site-nav-right,.site-nav-toggle{display:none}.site-nav-right .toggle,.site-nav-toggle .toggle{color:var(--text-color);padding:10px;width:22px}.site-nav-right .toggle .toggle-line,.site-nav-toggle .toggle .toggle-line{background:var(--text-color);border-radius:1px}@media (max-width:767px){.site-nav-right,.site-nav-toggle{display:flex;flex-direction:column;justify-content:center}.site-nav{--scroll-height:0;height:0;overflow:hidden;transition:height .2s ease-in-out}body:not(.site-nav-on) .site-nav .animated{animation:none}body.site-nav-on .site-nav{height:var(--scroll-height)}}.menu{margin:0;padding:1em 0;text-align:center}.menu-item{display:inline-block;list-style:none;margin:0 10px}@media (max-width:767px){.menu-item{display:block;margin-top:10px}.menu-item.menu-item-search{display:none}}.menu-item a{border-bottom:0;display:block;font-size:.8125em;transition:border-color .2s ease-in-out}.menu-item a.menu-item-active,.menu-item a:hover{background:var(--menu-item-bg-color)}.menu-item .fa,.menu-item .fab,.menu-item .far,.menu-item .fas{margin-right:8px}.menu-item .badge{display:inline-block;font-weight:700;line-height:1;margin-left:.35em;margin-top:.35em;text-align:center;white-space:nowrap}.use-motion .menu-item{visibility:hidden}.github-corner :hover .octo-arm{animation:560ms ease-in-out octocat-wave}.github-corner svg{color:#fff;fill:var(--theme-color);position:absolute;right:0;top:0;z-index:5}@media (max-width:991px){.github-corner{display:none}.github-corner svg{color:var(--theme-color);fill:#fff}.github-corner .github-corner:hover .octo-arm{animation:none}.github-corner .github-corner .octo-arm{animation:560ms ease-in-out octocat-wave}}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}.sidebar-inner{color:#999;padding:18px 10px;text-align:center;display:flex;flex-direction:column;justify-content:center}.cc-license .cc-opacity{border-bottom:0;opacity:.7}.cc-license .cc-opacity:hover{opacity:.9}.cc-license img{display:inline-block}.site-author-image{border:1px solid #eee;max-width:120px;padding:2px}.site-author-name{color:var(--text-color);font-weight:600;margin:0}.site-description{color:#999;font-size:.8125em;margin-top:0}.links-of-author a{font-size:.8125em}.links-of-author .fa,.links-of-author .fab,.links-of-author .far,.links-of-author .fas{margin-right:2px}.sidebar .sidebar-button:not(:first-child){margin-top:15px}.sidebar .sidebar-button button{background:0 0;cursor:pointer;line-height:2;padding:0 15px;border-radius:4px}.sidebar .sidebar-button button .fa,.sidebar .sidebar-button button .fab,.sidebar .sidebar-button button .far,.sidebar .sidebar-button button .fas{margin-right:5px}.links-of-blogroll{font-size:.8125em}.links-of-blogroll-title{font-size:.875em;font-weight:600}.links-of-blogroll-list{list-style:none;margin:0;padding:0}.sidebar-nav{display:none;margin:0;padding-bottom:20px;padding-left:0}.sidebar-nav-active .sidebar-nav{display:block}.sidebar-nav li{border-bottom:1px solid transparent;color:var(--text-color);cursor:pointer;display:inline-block;font-size:.875em}.sidebar-nav li.sidebar-nav-overview{margin-left:10px}.sidebar-nav li:hover{color:#fc6423}.sidebar-overview-active .sidebar-nav-overview,.sidebar-toc-active .sidebar-nav-toc{border-bottom-color:#fc6423;color:#fc6423}.sidebar-overview-active .sidebar-nav-overview:hover,.sidebar-toc-active .sidebar-nav-toc:hover{color:#fc6423}.sidebar-panel-container{flex:1;overflow-x:hidden;overflow-y:auto}.sidebar-panel{display:none}.sidebar-overview-active .site-overview-wrap{display:flex;flex-direction:column;justify-content:center;gap:10px}.sidebar-toc-active .post-toc-wrap{display:block}.sidebar-toggle{bottom:61px;height:16px;padding:5px;width:16px;background:#222;cursor:pointer;opacity:.6;position:fixed;z-index:30;right:30px}.sidebar-toggle:hover{opacity:.8}@media (max-width:991px){.sidebar-toggle{right:20px;opacity:.8}}.sidebar-toggle:hover .toggle-line{background:#fc6423}@media (any-hover:hover){body:not(.sidebar-active) .sidebar-toggle:hover :first-child{left:50%;top:2px;transform:rotate(45deg);width:50%}body:not(.sidebar-active) .sidebar-toggle:hover :last-child{left:50%;top:-2px;transform:rotate(-45deg);width:50%}}.sidebar-active .sidebar-toggle :nth-child(2){opacity:0}.sidebar-active .sidebar-toggle :first-child{top:6px;transform:rotate(45deg)}.sidebar-active .sidebar-toggle :last-child{top:-6px;transform:rotate(-45deg)}.post-toc{font-size:.875em}.post-toc ol{list-style:none;margin:0;padding:0 2px 5px 10px;text-align:left}.post-toc ol>ol{padding-left:0}.post-toc ol a{transition:.2s ease-in-out}.post-toc .nav-item{line-height:1.8;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.post-toc .nav .nav-child{display:none}.post-toc .nav .active-current>.nav-child,.post-toc .nav .active-current>.nav-child>.nav-item,.post-toc .nav .active>.nav-child{display:block}.post-toc .nav .active>a{border-bottom-color:#fc6423;color:#fc6423}.post-toc .nav .active-current>a,.post-toc .nav .active-current>a:hover{color:#fc6423}.site-state{display:flex;flex-wrap:wrap;justify-content:center;line-height:1.4}.site-state-item a{border-bottom:0;display:block}.site-state-item-count{display:block;font-size:1em;font-weight:600}.site-state-item-name{color:#999;font-size:.8125em}.sidebar-post-related{font-size:.8125em;padding:18px 0 0}.popular-posts{margin:0;padding:1em 0;text-align:left}.popular-posts .popular-posts-item{display:block}.popular-posts .popular-posts-item .popular-posts-link{border-bottom:0;display:block;padding:5px 20px;transition:background .2s ease-in-out}.popular-posts .popular-posts-item .popular-posts-link:hover{background:var(--menu-item-bg-color)}.popular-posts .popular-posts-item .popular-posts-time{color:#999}.footer{color:#999;font-size:.875em;padding:20px 0}.footer.footer-fixed{bottom:0;left:0;position:absolute;right:0}.footer-inner{box-sizing:border-box;text-align:center;display:flex;flex-direction:column;justify-content:center;margin:0 auto;width:calc(100% - 20px)}@media (max-width:767px){.menu-item .badge{float:right;margin-left:0}.footer-inner{width:auto}}@media (min-width:1200px){.footer-inner{width:1160px}}@media (min-width:1600px){.footer-inner{width:73%}}.use-motion .footer{opacity:0}.languages{display:inline-block;font-size:1.125em;position:relative}.languages .lang-select-label span{margin:0 .5em}.languages .lang-select{height:100%;left:0;opacity:0;position:absolute;top:0;width:100%}.with-love{color:red;display:inline-block;margin:0 5px}.beian img{display:inline-block;margin:0 3px;vertical-align:middle}.busuanzi-count #busuanzi_container_site_pv,.busuanzi-count #busuanzi_container_site_uv{display:none}@keyframes icon-animate{0%,100%{transform:scale(1)}10%,30%{transform:scale(.9)}20%,40%,50%,60%,70%,80%{transform:scale(1.1)}}@media (max-width:567px){.main-inner{padding:initial!important}.posts-expand .post-header{margin-bottom:10px!important}.post-block{margin-top:initial!important;padding:8px 18px!important}.post-body h1,.post-body h2,.post-body h3,.post-body h4,.post-body h5,.post-body h6{margin:20px 0 8px}.post-body .note h1,.post-body .note h2,.post-body .note h3,.post-body .note h4,.post-body .note h5,.post-body .note h6,.post-body .tabs .tab-content .tab-pane h1,.post-body .tabs .tab-content .tab-pane h2,.post-body .tabs .tab-content .tab-pane h3,.post-body .tabs .tab-content .tab-pane h4,.post-body .tabs .tab-content .tab-pane h5,.post-body .tabs .tab-content .tab-pane h6{margin:0 5px}.post-body>p{margin:0 0 10px}.post-body .note>p,.post-body .tabs .tab-content .tab-pane>p{padding:0 5px}.post-body img,.post-body video{margin-bottom:10px!important}.post-body .note{margin-bottom:10px!important;padding:10px!important}.post-body .tabs .tab-content .tab-pane{padding:10px 10px 0!important}.post-eof{margin:40px auto 20px!important}.pagination{margin-top:40px}}.back-to-top{font-size:12px;align-items:center;bottom:-100px;color:#fff;display:flex;height:26px;transition:bottom .2s ease-in-out;background:#222;cursor:pointer;opacity:.6;position:fixed;z-index:30;right:30px}.back-to-top span{margin-right:8px;display:none}.back-to-top .fa{text-align:center;width:26px}.back-to-top:hover{opacity:.8;color:#fc6423}.back-to-top.back-to-top-on{bottom:30px}.rtl.post-body a,.rtl.post-body h1,.rtl.post-body h2,.rtl.post-body h3,.rtl.post-body h4,.rtl.post-body h5,.rtl.post-body h6,.rtl.post-body li,.rtl.post-body ol,.rtl.post-body p,.rtl.post-body ul{direction:rtl;font-family:UKIJ Ekran}.rtl.post-title{font-family:UKIJ Ekran}.post-button{margin-top:40px;text-align:center}.use-motion .collection-header,.use-motion .comments,.use-motion .pagination,.use-motion .post-block,.use-motion .post-body,.use-motion .post-header{visibility:hidden}.posts-collapse .post-content{margin-bottom:35px;margin-left:35px;position:relative}@media (max-width:767px){.posts-collapse .post-content{margin-left:0;margin-right:0}}.posts-collapse .post-content .collection-title{font-size:1.125em;position:relative}.posts-collapse .post-content .collection-title::before{background:#999;border:1px solid #fff;margin-left:-6px;margin-top:-4px;position:absolute;top:50%;border-radius:50%;content:' ';height:10px;width:10px}.posts-collapse .post-content .collection-year{font-size:1.5em;font-weight:700;margin:60px 0;position:relative}.posts-collapse .post-content .collection-year::before{background:#bbb;margin-left:-4px;margin-top:-4px;position:absolute;top:50%;border-radius:50%;content:' ';height:8px;width:8px}.posts-collapse .post-content .collection-header{display:block;margin-left:20px}.posts-collapse .post-content .collection-header small{color:#bbb;margin-left:5px}.posts-collapse .post-content .post-header{border-bottom:1px dashed #ccc;margin:30px 2px 0;padding-left:15px;position:relative;transition:border .2s ease-in-out}.posts-collapse .post-content .post-header::before{background:#bbb;border:1px solid #fff;left:-6px;position:absolute;top:.75em;transition:background .2s ease-in-out;border-radius:50%;content:' ';height:6px;width:6px}.posts-collapse .post-content .post-header:hover{border-bottom-color:#666}.posts-collapse .post-content .post-header:hover::before{background:#222}.posts-collapse .post-content .post-meta-container{display:inline;font-size:.75em;margin-right:10px}.posts-collapse .post-content .post-title{display:inline}.posts-collapse .post-content .post-title a{border-bottom:0;color:var(--link-color)}.posts-collapse .post-content .post-title .fa-external-link-alt{font-size:.875em;margin-left:5px}.posts-collapse .post-content::before{background:#f5f5f5;content:' ';height:100%;margin-left:-2px;position:absolute;top:1.25em;width:4px}.post-body{font-family:Lato,'PingFang SC','Microsoft YaHei',sans-serif;overflow-wrap:break-word}@media (min-width:1200px){.post-body{font-size:1.125em}}@media (min-width:992px){.post-body{text-align:justify}}.post-body h1 .header-anchor,.post-body h1 .headerlink,.post-body h2 .header-anchor,.post-body h2 .headerlink,.post-body h3 .header-anchor,.post-body h3 .headerlink,.post-body h4 .header-anchor,.post-body h4 .headerlink,.post-body h5 .header-anchor,.post-body h5 .headerlink,.post-body h6 .header-anchor,.post-body h6 .headerlink{border-bottom-style:none;color:inherit;float:right;font-size:.875em;margin-left:10px;opacity:0}.post-body h1 .header-anchor::before,.post-body h1 .headerlink::before,.post-body h2 .header-anchor::before,.post-body h2 .headerlink::before,.post-body h3 .header-anchor::before,.post-body h3 .headerlink::before,.post-body h4 .header-anchor::before,.post-body h4 .headerlink::before,.post-body h5 .header-anchor::before,.post-body h5 .headerlink::before,.post-body h6 .header-anchor::before,.post-body h6 .headerlink::before{content:'\f0c1';font-family:'Font Awesome 6 Free';font-weight:900}.post-body h1:hover .header-anchor,.post-body h1:hover .headerlink,.post-body h2:hover .header-anchor,.post-body h2:hover .headerlink,.post-body h3:hover .header-anchor,.post-body h3:hover .headerlink,.post-body h4:hover .header-anchor,.post-body h4:hover .headerlink,.post-body h5:hover .header-anchor,.post-body h5:hover .headerlink,.post-body h6:hover .header-anchor,.post-body h6:hover .headerlink{opacity:.5}.post-body h1:hover .header-anchor:hover,.post-body h1:hover .headerlink:hover,.post-body h2:hover .header-anchor:hover,.post-body h2:hover .headerlink:hover,.post-body h3:hover .header-anchor:hover,.post-body h3:hover .headerlink:hover,.post-body h4:hover .header-anchor:hover,.post-body h4:hover .headerlink:hover,.post-body h5:hover .header-anchor:hover,.post-body h5:hover .headerlink:hover,.post-body h6:hover .header-anchor:hover,.post-body h6:hover .headerlink:hover{opacity:1}.post-body .exturl .fa{font-size:.875em;margin-left:4px}.post-body .fancybox+figcaption,.post-body .image-caption,.post-body img+figcaption{color:#999;font-size:.875em;font-weight:700;line-height:1;margin:-15px auto 15px;text-align:center}.post-body embed,.post-body iframe,.post-body img,.post-body video{margin-bottom:20px}.post-body .video-container{height:0;margin-bottom:20px;overflow:hidden;padding-top:75%;position:relative;width:100%}.post-body .video-container embed,.post-body .video-container iframe,.post-body .video-container object{height:100%;left:0;margin:0;position:absolute;top:0;width:100%}.post-gallery{display:flex;min-height:200px}.post-gallery .post-gallery-image{flex:1}.post-gallery .post-gallery-image:not(:first-child){clip-path:polygon(40px 0,100% 0,100% 100%,0 100%);margin-left:-20px}.post-gallery .post-gallery-image:not(:last-child){margin-right:-20px}.post-gallery .post-gallery-image img{height:100%;object-fit:cover;opacity:1;width:100%}.posts-expand .post-gallery{margin-bottom:60px}.posts-collapse .post-gallery{margin:15px 0}.posts-expand .post-header{font-size:1.125em;margin-bottom:60px;text-align:center}.posts-expand .post-title{font-size:1.5em;font-weight:400;margin:initial;overflow-wrap:break-word}.posts-expand .post-title-link{border-bottom:0;color:var(--link-color);display:inline-block;position:relative}.posts-expand .post-title-link::before{background:var(--link-color);bottom:0;content:'';height:2px;left:0;position:absolute;transform:scaleX(0);transition:transform .2s ease-in-out;width:100%}.posts-expand .post-title-link:hover::before{transform:scaleX(1)}.posts-expand .post-title-link .fa-external-link-alt{font-size:.875em;margin-left:5px}.post-sticky-flag{display:inline-block;margin-right:8px;transform:rotate(30deg)}.posts-expand .post-meta-container{color:#999;font-family:Lato,'PingFang SC','Microsoft YaHei',sans-serif;font-size:.75em;margin-top:3px}.posts-expand .post-meta-container .post-description{font-size:.875em;margin-top:2px}.posts-expand .post-meta-container time{border-bottom:1px dashed #999}.post-meta{display:flex;flex-wrap:wrap;justify-content:center}:not(.post-meta-break)+.post-meta-item::before{content:'|';margin:0 .5em}.post-meta-item-icon{margin-right:3px}@media (max-width:991px){.back-to-top{right:20px;opacity:.8}.post-body{text-align:justify}.post-meta-item-text{display:none}}.post-meta-break{flex-basis:100%;height:0}#busuanzi_container_page_pv{display:none}.post-nav{border-top:1px solid #eee;display:flex;gap:30px;justify-content:space-between;margin-top:1em;padding:10px 5px 0}.post-nav-item{flex:1}.post-nav-item a{border-bottom:0;display:block;font-size:.875em;line-height:1.6}.post-nav-item a:active{top:2px}.post-nav-item .fa{font-size:.75em}.post-nav-item:first-child .fa{margin-right:5px}.post-nav-item:last-child{text-align:right}.post-nav-item:last-child .fa{margin-left:5px}.post-footer{display:flex;flex-direction:column;justify-content:center}.post-eof{background:#ccc;height:1px;margin:80px auto 60px;width:8%}.post-block:last-of-type .post-eof{display:none}.post-copyright ul{list-style:none;overflow:hidden;padding:.5em 1em;position:relative;background:var(--card-bg-color);border-left:3px solid #ff2a2a;margin:1em 0 0}.post-copyright ul::after{content:'\f25e';font-family:'Font Awesome 6 Brands';font-size:200px;opacity:.1;position:absolute;right:-50px;top:-150px}.post-tags{margin-top:40px;text-align:center}.post-tags a{display:inline-block;font-size:.8125em}.post-tags a:not(:last-child){margin-right:10px}.social-like{border-top:1px solid #eee;font-size:.875em;margin-top:1em;padding-top:1em;text-align:center}.reward-container{margin:1em 0 0;padding:1em 0;text-align:center}.reward-container button{background:0 0;color:#fc6423;cursor:pointer;line-height:2;padding:0 15px;border:2px solid #fc6423;border-radius:2px;outline:0;transition:.2s ease-in-out;vertical-align:text-top}.reward-container button:hover{background:#fc6423;color:#fff}.post-reward{display:none;padding-top:20px}.post-reward.active{display:block}.post-reward div{display:inline-block}.post-reward div span{display:block}.post-reward img{display:inline-block;margin:.8em 2em 0;max-width:100%;width:180px}@keyframes next-roll{from{transform:rotateZ(30deg)}to{transform:rotateZ(-30deg)}}.category-all-page .category-all-title{text-align:center}.category-all-page .category-all{margin-top:20px}.category-all-page .category-list{list-style:none;margin:0;padding:0}.category-all-page .category-list-item{margin:5px 10px}.category-all-page .category-list-count{color:#bbb}.category-all-page .category-list-count::before{content:' ('}.category-all-page .category-list-count::after{content:') '}.category-all-page .category-list-child{padding-left:10px}.event-list hr{background:#222;margin:20px 0 45px}.event-list hr::after{background:#222;color:#fff;content:'NOW';display:inline-block;font-weight:700;padding:0 5px}.event-list .event{--event-background:#222;--event-foreground:#bbb;--event-title:#fff;background:var(--event-background);padding:15px}.event-list .event .event-summary{border-bottom:0;color:var(--event-title);margin:0;padding:0 0 0 35px;position:relative}.event-list .event .event-summary::before{animation:1s ease-in-out infinite alternate dot-flash;background:var(--event-title);left:0;margin-top:-6px;position:absolute;top:50%;border-radius:50%;content:' ';height:12px;width:12px}.event-list .event:nth-of-type(odd) .event-summary::before{animation-delay:.5s}.event-list .event:not(:last-child){margin-bottom:20px}.event-list .event .event-relative-time{color:var(--event-foreground);display:inline-block;font-size:12px;font-weight:400;padding-left:12px}.event-list .event .event-details{color:var(--event-foreground);display:block;line-height:18px;padding:6px 0 6px 35px}.event-list .event .event-details::before{color:var(--event-foreground);display:inline-block;margin-right:9px;width:14px;font-family:'Font Awesome 6 Free';font-weight:900}.event-list .event .event-details.event-location::before{content:'\f041'}.event-list .event .event-details.event-duration::before{content:'\f017'}.event-list .event .event-details.event-description::before{content:'\f024'}.event-list .event-past{--event-background:#f5f5f5;--event-foreground:#999;--event-title:#222}@keyframes dot-flash{from{opacity:1;transform:scale(1)}to{opacity:0;transform:scale(.8)}}ul.breadcrumb{font-size:.75em;list-style:none;margin:1em 0;padding:0 2em;text-align:center}ul.breadcrumb li{display:inline}ul.breadcrumb li:not(:first-child)::before{content:'/\00a0';font-weight:400;padding:.5em}ul.breadcrumb li:last-child{font-weight:700}.tag-cloud{text-align:center}.tag-cloud a{display:inline-block;margin:10px}.tag-cloud-0{border-bottom-color:#aaa;color:#aaa}.tag-cloud-1{border-bottom-color:#9a9a9a;color:#9a9a9a}.tag-cloud-2{border-bottom-color:#8b8b8b;color:#8b8b8b}.tag-cloud-3{border-bottom-color:#7c7c7c;color:#7c7c7c}.tag-cloud-4{border-bottom-color:#6c6c6c;color:#6c6c6c}.tag-cloud-5{border-bottom-color:#5d5d5d;color:#5d5d5d}.tag-cloud-6{border-bottom-color:#4e4e4e;color:#4e4e4e}.tag-cloud-7{border-bottom-color:#3e3e3e;color:#3e3e3e}.tag-cloud-8{border-bottom-color:#2f2f2f;color:#2f2f2f}.tag-cloud-9{border-bottom-color:#202020;color:#202020}.tag-cloud-10{border-bottom-color:#111;color:#111}.search-active{overflow:hidden}.search-pop-overlay{background:rgba(0,0,0,0);display:flex;height:100%;left:0;position:fixed;top:0;transition:visibility .4s,background .4s;visibility:hidden;width:100%;z-index:40}.search-active .search-pop-overlay{background:rgba(0,0,0,.3);visibility:visible}.search-popup{background:var(--card-bg-color);border-radius:5px;height:80%;margin:auto;transform:scale(0);transition:transform .4s;width:700px}.search-active .search-popup{transform:scale(1)}@media (max-width:767px){.search-popup{border-radius:0;height:100%;width:100%}}.search-popup .popup-btn-close,.search-popup .search-icon{color:#999;font-size:18px;padding:0 10px}.search-popup .popup-btn-close{cursor:pointer}.search-popup .popup-btn-close:hover .fa{color:#222}.search-popup .search-header{background:#eee;border-top-left-radius:5px;border-top-right-radius:5px;display:flex;padding:5px}.search-popup input.search-input{background:0 0;border:0;outline:0;width:100%}.search-popup input.search-input::-webkit-search-cancel-button{display:none}.search-popup .search-result-container{height:calc(100% - 55px);overflow:auto;padding:5px 25px}.search-popup .search-result-container hr{margin:5px 0 10px}.search-popup .search-result-container hr:first-child{display:none}.search-popup .search-result-list{margin:0 5px;padding:0}.search-popup a.search-result-title{font-weight:700}.search-popup p.search-result{border-bottom:1px dashed #ccc;padding:5px 0}.search-input-container{flex-grow:1}.search-input-container form{padding:2px}.search-stats{align-items:center;display:flex;justify-content:space-between}.search-stats img{height:1em;margin:0}.algolia-pagination{margin:40px 0;opacity:1;padding:0}.algolia-pagination .pagination-item{display:inline-block}.algolia-pagination .current .page-number{cursor:default}.algolia-pagination .disabled-item{visibility:hidden}.use-motion .animated{animation-fill-mode:none;visibility:inherit}.use-motion .sidebar .animated{animation-fill-mode:both}.header{background:var(--content-bg-color);border-radius:initial;box-shadow:initial}.main{align-items:stretch;display:flex;justify-content:space-between;margin:0 auto;width:calc(100% - 20px)}@media (max-width:767px){.main{width:auto}}@media (min-width:1200px){.main{width:1160px}}@media (min-width:1600px){.main{width:73%}}@media (max-width:991px){.header{border-radius:initial}.main{display:block;width:auto}}.main-inner{border-radius:initial;box-sizing:border-box;width:calc(100% - 252px)}.footer-inner{padding-left:252px}@media (max-width:991px){.main-inner{border-radius:initial;width:100%}.footer-inner{padding-left:0;padding-right:0;width:auto}}.column{width:240px}.site-brand-container{background:var(--theme-color)}.site-meta{padding:20px 0}.site-nav-right .toggle,.site-nav-toggle .toggle{color:#fff}.site-nav-right .toggle .toggle-line,.site-nav-toggle .toggle .toggle-line{background:#fff}@media (min-width:768px) and (max-width:991px){.site-nav-right,.site-nav-toggle{display:flex;flex-direction:column;justify-content:center}.site-nav{--scroll-height:0;height:0;overflow:hidden;transition:height .2s ease-in-out}body:not(.site-nav-on) .site-nav .animated{animation:none}body.site-nav-on .site-nav{height:var(--scroll-height)}}.menu .menu-item{display:block;margin:0}.menu .menu-item a{padding:5px 20px;position:relative;text-align:left;transition-property:background-color}.menu .menu-item .badge{background:#ccc;border-radius:10px;color:var(--content-bg-color);float:right;padding:2px 5px;text-shadow:1px 1px 0 rgba(0,0,0,.1)}.main-menu .menu-item-active::after{background:#bbb;border-radius:50%;content:' ';height:6px;margin-top:-3px;position:absolute;right:15px;top:50%;width:6px}.sub-menu{margin:0;padding:6px 0}.sub-menu .menu-item{display:inline-block}.sub-menu .menu-item a{background:0 0;margin:5px 10px;padding:initial}.sub-menu .menu-item a:hover{background:0 0;color:#fc6423}.sub-menu .menu-item-active{border-bottom-color:#fc6423;color:#fc6423}.sub-menu .menu-item-active:hover{border-bottom-color:#fc6423}.sidebar{position:-webkit-sticky;position:sticky;top:12px}@media (max-width:991px){.column{width:auto}.site-nav-on .site-brand-container{box-shadow:0 0 16px rgba(0,0,0,.5)}.menu .menu-item.menu-item-search,.sidebar{display:none}}.sidebar-inner{background:var(--content-bg-color);border-radius:initial;box-shadow:initial;box-sizing:border-box;color:var(--text-color);margin-top:12px;max-height:calc(100vh - 24px);visibility:hidden}.site-state-item{padding:0 10px}.sidebar .sidebar-button{border-bottom:1px dotted #ccc;border-top:1px dotted #ccc}.sidebar .sidebar-button button{border:0;color:#fc6423;display:block;width:100%}.sidebar .sidebar-button button:hover{background:0 0;border:0;color:#e34603}.links-of-author{display:flex;flex-wrap:wrap;justify-content:center}.links-of-author-item{margin:5px 0 0;width:50%}.links-of-author-item a{box-sizing:border-box;max-width:100%;overflow:hidden;padding:0 5px;text-overflow:ellipsis;white-space:nowrap;border-bottom:0;border-radius:4px;display:block}.links-of-author-item a:hover{background:var(--body-bg-color)}.main-inner{background:var(--content-bg-color);box-shadow:initial;padding:40px}@media (max-width:991px){.main-inner{padding:20px}}.sub-menu{border-bottom:1px solid #ddd}.post-block:first-of-type{padding-top:40px}@media (max-width:767px){.pagination{margin-bottom:10px}}</style><link as=style href=https://fonts.googleapis.com/css?family=Lato:300,300italic,400,400italic,700,700italic&display=swap&subset=latin,latin-ext onload=this.rel='stylesheet' rel=preload><link crossorigin=anonymous href=https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/css/all.min.css integrity=sha256-Z1K5uhUaJXA7Ll0XrZ/0JhX4lAtZFpT6jkKrEDT0drU= rel=stylesheet><link crossorigin=anonymous href=https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.1.1/animate.min.css integrity=sha256-PR7ttpcvz8qrF57fur/yAx1qXMFJeJFiA6pSzWi0OIE= rel=stylesheet><link crossorigin=anonymous href=https://cdnjs.cloudflare.com/ajax/libs/fancybox/3.5.7/jquery.fancybox.min.css integrity=sha256-Vzbj7sDDS/woiFS3uNKo8eIuni59rjyNGtXfstRzStA= rel=stylesheet><script class=next-config data-name=main type=application/json>{"hostname":"nicksxs.me","root":"/","images":"/images","scheme":"Pisces","darkmode":false,"version":"8.14.1","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12},"copycode":{"enable":true,"style":"mac"},"bookmark":{"enable":false,"color":"#222","save":"auto"},"mediumzoom":false,"lazyload":true,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"stickytabs":false,"motion":{"enable":true,"async":false,"transition":{"menu_item":"fadeInDown","post_block":"fadeIn","post_header":"fadeInDown","post_body":"fadeInDown","coll_header":"fadeInLeft","sidebar":"fadeInUp"}},"prism":false,"i18n":{"placeholder":"搜索...","empty":"没有找到任何搜索结果:${query}","hits_time":"找到 ${hits} 个搜索结果(用时 ${time} 毫秒)","hits":"找到 ${hits} 个搜索结果"},"algolia":{"appID":"663Q99OQQD","apiKey":"e461a1371d12cec1491c1153b288a9ed","indexName":"nicksxs","hits":{"per_page":10}}}</script><script src=/js/config.js></script><meta content="learn from zero,技术博客,Nicksxs,史学森" name=description><meta content=website property=og:type><meta content="Nicksxs's Blog" property=og:title><meta content=https://nicksxs.me/page/29/index.html property=og:url><meta content="Nicksxs's Blog" property=og:site_name><meta content="learn from zero,技术博客,Nicksxs,史学森" property=og:description><meta content=zh_CN property=og:locale><meta content=Nicksxs property=article:author><meta content=Nicksxs,史学森,米方方,米方方的男朋友,森哥 property=article:tag><meta content=summary name=twitter:card><link href=https://nicksxs.me/page/29/ rel=canonical><script class=next-config data-name=page type=application/json>{"sidebar":"","isHome":true,"isPost":false,"lang":"zh-CN","comments":"","permalink":"","path":"page/29/index.html","title":""}</script><script class=next-config data-name=calendar type=application/json>""</script><title>Nicksxs's Blog - What hurts more, the pain of hard work or the pain of regret?</title><script async src=https://www.googletagmanager.com/gtag/js?id=UA-61358619-1></script><script class=next-config data-name=google_analytics type=application/json>{"tracking_id":"UA-61358619-1","only_pageview":false}</script><script src=/js/third-party/analytics/google-analytics.js></script><script src=/js/third-party/analytics/baidu-analytics.js></script><script async src=https://hm.baidu.com/hm.js?20f33b3c0c0eff9b1522999c0015646d></script><noscript><link href=/css/noscript.css rel=stylesheet></noscript><link title="Nicksxs's Blog" href=/atom.xml rel=alternate type=application/atom+xml><body class=use-motion itemscope itemtype=http://schema.org/WebPage><div class=headband></div><main class=main><div class=column><header class=header itemscope itemtype=http://schema.org/WPHeader><div class=site-brand-container><div class=site-nav-toggle><div aria-label=切换导航栏 class=toggle role=button><span class=toggle-line></span><span class=toggle-line></span><span class=toggle-line></span></div></div><div class=site-meta><a class=brand href=/ rel=start><i class=logo-line></i><h1 class=site-title>Nicksxs's Blog</h1><i class=logo-line></i></a><p class=site-subtitle itemprop=description>What hurts more, the pain of hard work or the pain of regret?</div><div class=site-nav-right><div class="toggle popup-trigger" aria-label=搜索 role=button><i class="fa fa-search fa-fw fa-lg"></i></div></div></div><nav class=site-nav><ul class="main-menu menu"><li class="menu-item menu-item-home"><a href=/ rel=section><i class="fa fa-home fa-fw"></i>首页</a><li class="menu-item menu-item-about"><a href=/about/ rel=section><i class="fa fa-user fa-fw"></i>关于</a><li class="menu-item menu-item-tags"><a href=/tags/ rel=section><i class="fa fa-tags fa-fw"></i>标签</a><li class="menu-item menu-item-categories"><a href=/categories/ rel=section><i class="fa fa-th fa-fw"></i>分类</a><li class="menu-item menu-item-archives"><a href=/archives/ rel=section><i class="fa fa-archive fa-fw"></i>归档</a><li class="menu-item menu-item-top"><a href=/top/ rel=section><i class="fa fa-th fa-fw"></i>热度</a><li class="menu-item menu-item-sitemap"><a href=/sitemap.xml rel=section><i class="fa fa-sitemap fa-fw"></i>站点地图</a><li class="menu-item menu-item-commonweal"><a href=/404/ rel=section><i class="fa fa-heartbeat fa-fw"></i>公益 404</a><li class="menu-item menu-item-search"><a class=popup-trigger role=button><i class="fa fa-search fa-fw"></i>搜索</a></ul></nav><div class=search-pop-overlay><div class="popup search-popup"><div class=search-header><span class=search-icon><i class="fa fa-search"></i></span><div class=search-input-container></div><span class=popup-btn-close role=button><i class="fa fa-times-circle"></i></span></div><div class=search-result-container><div class=algolia-stats><hr></div><div class=algolia-hits></div><div class=algolia-pagination></div></div></div></div></header><aside class=sidebar><div class="sidebar-inner sidebar-overview-active"><ul class=sidebar-nav><li class=sidebar-nav-toc>文章目录<li class=sidebar-nav-overview>站点概览</ul><div class=sidebar-panel-container><div class="post-toc-wrap sidebar-panel"></div><div class="site-overview-wrap sidebar-panel"><div class="site-author animated" itemprop=author itemscope itemtype=http://schema.org/Person><img alt=Nicksxs class=site-author-image itemprop=image src=/uploads/avatar.jpg><p class=site-author-name itemprop=name>Nicksxs<div class=site-description itemprop=description>learn from zero,技术博客,Nicksxs,史学森</div></div><div class="site-state-wrap animated"><nav class=site-state><div class="site-state-item site-state-posts"><a href=/archives/><span class=site-state-item-count>233</span> <span class=site-state-item-name>日志</span></a></div><div class="site-state-item site-state-categories"><a href=/categories/><span class=site-state-item-count>159</span> <span class=site-state-item-name>分类</span></a></div><div class="site-state-item site-state-tags"><a href=/tags/><span class=site-state-item-count>296</span> <span class=site-state-item-name>标签</span></a></div></nav></div><div class="links-of-author animated"><span class=links-of-author-item><a rel="noopener me" title="GitHub → https://github.com/nicksxs" href=https://github.com/nicksxs target=_blank><i class="fab fa-github fa-fw"></i>GitHub</a> </span><span class=links-of-author-item><a rel="noopener me" title="E-Mail → mailto:nicksxs1202@gmail.com" href=mailto:nicksxs1202@gmail.com target=_blank><i class="fa fa-envelope fa-fw"></i>E-Mail</a></span></div><div class="cc-license animated" itemprop=license><a class=cc-opacity href=https://creativecommons.org/licenses/by-nc-sa/4.0/ rel=noopener target=_blank><img alt="Creative Commons" src=https://cdnjs.cloudflare.com/ajax/libs/creativecommons-vocabulary/2020.11.3/assets/license_badges/small/by_nc_sa.svg></a></div><div class=post-gallery itemscope itemtype=http://schema.org/ImageGallery style=height:120px;min-height:120px><div class=post-gallery-row><a class="post-gallery-img fancybox" href=https://url.cn/LLWrL7gx itemprop=url itemscope itemtype=http://schema.org/ImageObject rel=gallery_ target=_blank><img alt=腾讯云推广 itemprop=contentUrl src=https://img.nicksxs.com/blog/345X200.jpg style=padding:12px></a></div></div><script charset=utf-8 src=/js/tagcloud.js></script><script charset=utf-8 src=/js/tagcanvas.js></script><div class=widget-wrap><div class="widget tagcloud" id=myCanvasContainer><canvas height=250 id=resCanvas width=250><ul class=tag-list itemprop=keywords><li class=tag-list-item><a class=tag-list-link href=/tags/2019/ rel=tag>2019</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/2020/ rel=tag>2020</a><span class=tag-list-count>2</span><li class=tag-list-item><a class=tag-list-link href=/tags/2021/ rel=tag>2021</a><span class=tag-list-count>3</span><li class=tag-list-item><a class=tag-list-link href=/tags/2022/ rel=tag>2022</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/2023/ rel=tag>2023</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/2PC/ rel=tag>2PC</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/360-%E5%85%A8%E5%AE%B6%E6%A1%B6/ rel=tag>360 全家桶</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/3PC/ rel=tag>3PC</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/3Sum-Closest/ rel=tag>3Sum Closest</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/AOP/ rel=tag>AOP</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/Adaptive/ rel=tag>Adaptive</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/Apollo/ rel=tag>Apollo</a><span class=tag-list-count>3</span><li class=tag-list-item><a class=tag-list-link href=/tags/AutoConfiguration/ rel=tag>AutoConfiguration</a><span class=tag-list-count>2</span><li class=tag-list-item><a class=tag-list-link href=/tags/Binary-Tree/ rel=tag>Binary Tree</a><span class=tag-list-count>3</span><li class=tag-list-item><a class=tag-list-link href=/tags/Broker/ rel=tag>Broker</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/C/ rel=tag>C</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/C/ rel=tag>C++</a><span class=tag-list-count>3</span><li class=tag-list-item><a class=tag-list-link href=/tags/CachedThreadPool/ rel=tag>CachedThreadPool</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/Comparator/ rel=tag>Comparator</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/DFS/ rel=tag>DFS</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/DP/ rel=tag>DP</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/DefaultMQPushConsumer/ rel=tag>DefaultMQPushConsumer</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/Design-Patterns/ rel=tag>Design Patterns</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/Disruptor/ rel=tag>Disruptor</a><span class=tag-list-count>3</span><li class=tag-list-item><a class=tag-list-link href=/tags/Distributed-Lock/ rel=tag>Distributed Lock</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/Docker/ rel=tag>Docker</a><span class=tag-list-count>5</span><li class=tag-list-item><a class=tag-list-link href=/tags/Dockerfile/ rel=tag>Dockerfile</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/Druid/ rel=tag>Druid</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/Dubbo/ rel=tag>Dubbo</a><span class=tag-list-count>6</span><li class=tag-list-item><a class=tag-list-link href=/tags/EagerThreadPool/ rel=tag>EagerThreadPool</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/Evict/ rel=tag>Evict</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/Filter/ rel=tag>Filter</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/First-Bad-Version/ rel=tag>First Bad Version</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/FixedThreadPool/ rel=tag>FixedThreadPool</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/G1/ rel=tag>G1</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/GC/ rel=tag>GC</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/Garbage-First-Collector/ rel=tag>Garbage-First Collector</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/Gogs/ rel=tag>Gogs</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/Homebrew/ rel=tag>Homebrew</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/Inorder-Traversal/ rel=tag>Inorder Traversal</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/Interceptor/ rel=tag>Interceptor</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/Intersection-of-Two-Arrays/ rel=tag>Intersection of Two Arrays</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/JMap/ rel=tag>JMap</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/JPS/ rel=tag>JPS</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/JStack/ rel=tag>JStack</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/JVM/ rel=tag>JVM</a><span class=tag-list-count>2</span><li class=tag-list-item><a class=tag-list-link href=/tags/Java/ rel=tag>Java</a><span class=tag-list-count>55</span><li class=tag-list-item><a class=tag-list-link href=/tags/Leetcode-42/ rel=tag>Leetcode 42</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/LimitedThreadPool/ rel=tag>LimitedThreadPool</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/Linked-List/ rel=tag>Linked List</a><span class=tag-list-count>2</span><li class=tag-list-item><a class=tag-list-link href=/tags/Lowest-Common-Ancestor-of-a-Binary-Tree/ rel=tag>Lowest Common Ancestor of a Binary Tree</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/MQ/ rel=tag>MQ</a><span class=tag-list-count>9</span><li class=tag-list-item><a class=tag-list-link href=/tags/Mac/ rel=tag>Mac</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/Maven/ rel=tag>Maven</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/Median-of-Two-Sorted-Arrays/ rel=tag>Median of Two Sorted Arrays</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/Mybatis/ rel=tag>Mybatis</a><span class=tag-list-count>13</span><li class=tag-list-item><a class=tag-list-link href=/tags/Mysql/ rel=tag>Mysql</a><span class=tag-list-count>13</span><li class=tag-list-item><a class=tag-list-link href=/tags/NameServer/ rel=tag>NameServer</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/PHP/ rel=tag>PHP</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/Preorder-Traversal/ rel=tag>Preorder Traversal</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/Print-FooBar-Alternately/ rel=tag>Print FooBar Alternately</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/RPC/ rel=tag>RPC</a><span class=tag-list-count>4</span><li class=tag-list-item><a class=tag-list-link href=/tags/Redis/ rel=tag>Redis</a><span class=tag-list-count>2</span><li class=tag-list-item><a class=tag-list-link href=/tags/Remove-Duplicates-from-Sorted-List/ rel=tag>Remove Duplicates from Sorted List</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/RocketMQ/ rel=tag>RocketMQ</a><span class=tag-list-count>9</span><li class=tag-list-item><a class=tag-list-link href=/tags/Rotate-Image/ rel=tag>Rotate Image</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/Rust/ rel=tag>Rust</a><span class=tag-list-count>3</span><li class=tag-list-item><a class=tag-list-link href=/tags/SPI/ rel=tag>SPI</a><span class=tag-list-count>2</span><li class=tag-list-item><a class=tag-list-link href=/tags/Servlet/ rel=tag>Servlet</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/Sharding-Jdbc/ rel=tag>Sharding-Jdbc</a><span class=tag-list-count>3</span><li class=tag-list-item><a class=tag-list-link href=/tags/Shift-2D-Grid/ rel=tag>Shift 2D Grid</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/Singleton/ rel=tag>Singleton</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/Spring/ rel=tag>Spring</a><span class=tag-list-count>7</span><li class=tag-list-item><a class=tag-list-link href=/tags/Spring-Event/ rel=tag>Spring Event</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/SpringBoot/ rel=tag>SpringBoot</a><span class=tag-list-count>15</span><li class=tag-list-item><a class=tag-list-link href=/tags/Sql%E6%B3%A8%E5%85%A5/ rel=tag>Sql注入</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/Stream/ rel=tag>Stream</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/Synchronized/ rel=tag>Synchronized</a><span class=tag-list-count>2</span><li class=tag-list-item><a class=tag-list-link href=/tags/Thread-dump/ rel=tag>Thread dump</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/ThreadLocal/ rel=tag>ThreadLocal</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/ThreadPool/ rel=tag>ThreadPool</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/Tomcat/ rel=tag>Tomcat</a><span class=tag-list-count>6</span><li class=tag-list-item><a class=tag-list-link href=/tags/Trapping-Rain-Water/ rel=tag>Trapping Rain Water</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/WeakReference/ rel=tag>WeakReference</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/Web/ rel=tag>Web</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/Webhook/ rel=tag>Webhook</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/Windows/ rel=tag>Windows</a><span class=tag-list-count>4</span><li class=tag-list-item><a class=tag-list-link href=/tags/WordPress/ rel=tag>WordPress</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/aqs/ rel=tag>aqs</a><span class=tag-list-count>3</span><li class=tag-list-item><a class=tag-list-link href=/tags/await/ rel=tag>await</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/bloom-filter/ rel=tag>bloom filter</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/c/ rel=tag>c++</a><span class=tag-list-count>14</span><li class=tag-list-item><a class=tag-list-link href=/tags/cglib/ rel=tag>cglib</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/cgroup/ rel=tag>cgroup</a><span class=tag-list-count>2</span><li class=tag-list-item><a class=tag-list-link href=/tags/cluster/ rel=tag>cluster</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/condition/ rel=tag>condition</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/dnsmasq/ rel=tag>dnsmasq</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/docker/ rel=tag>docker</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/dp/ rel=tag>dp</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/dubbo/ rel=tag>dubbo</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/echo/ rel=tag>echo</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/environment/ rel=tag>environment</a><span class=tag-list-count>2</span><li class=tag-list-item><a class=tag-list-link href=/tags/gap-lock/ rel=tag>gap lock</a><span class=tag-list-count>2</span><li class=tag-list-item><a class=tag-list-link href=/tags/gc/ rel=tag>gc</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/git/ rel=tag>git</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/grep/ rel=tag>grep</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/hadoop/ rel=tag>hadoop</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/headscale/ rel=tag>headscale</a><span class=tag-list-count>2</span><li class=tag-list-item><a class=tag-list-link href=/tags/hexo/ rel=tag>hexo</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/icu4c/ rel=tag>icu4c</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/im/ rel=tag>im</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/is-not-null/ rel=tag>is not null</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/is-null/ rel=tag>is null</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/j-u-c/ rel=tag>j.u.c</a><span class=tag-list-count>2</span><li class=tag-list-item><a class=tag-list-link href=/tags/java/ rel=tag>java</a><span class=tag-list-count>35</span><li class=tag-list-item><a class=tag-list-link href=/tags/jvm/ rel=tag>jvm</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/leetcode/ rel=tag>leetcode</a><span class=tag-list-count>40</span><li class=tag-list-item><a class=tag-list-link href=/tags/leetcode-155/ rel=tag>leetcode 155</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/linked-list/ rel=tag>linked list</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/linux/ rel=tag>linux</a><span class=tag-list-count>3</span><li class=tag-list-item><a class=tag-list-link href=/tags/lock/ rel=tag>lock</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/mfc/ rel=tag>mfc</a><span class=tag-list-count>2</span><li class=tag-list-item><a class=tag-list-link href=/tags/min-stack/ rel=tag>min stack</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/mq/ rel=tag>mq</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/mvcc/ rel=tag>mvcc</a><span class=tag-list-count>3</span><li class=tag-list-item><a class=tag-list-link href=/tags/mysql/ rel=tag>mysql</a><span class=tag-list-count>6</span><li class=tag-list-item><a class=tag-list-link href=/tags/namespace/ rel=tag>namespace</a><span class=tag-list-count>3</span><li class=tag-list-item><a class=tag-list-link href=/tags/nas/ rel=tag>nas</a><span class=tag-list-count>6</span><li class=tag-list-item><a class=tag-list-link href=/tags/next-key-lock/ rel=tag>next-key lock</a><span class=tag-list-count>2</span><li class=tag-list-item><a class=tag-list-link href=/tags/nginx/ rel=tag>nginx</a><span class=tag-list-count>3</span><li class=tag-list-item><a class=tag-list-link href=/tags/nullsfirst/ rel=tag>nullsfirst</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/openresty/ rel=tag>openresty</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/php/ rel=tag>php</a><span class=tag-list-count>4</span><li class=tag-list-item><a class=tag-list-link href=/tags/powershell/ rel=tag>powershell</a><span class=tag-list-count>2</span><li class=tag-list-item><a class=tag-list-link href=/tags/procedure/ rel=tag>procedure</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/python/ rel=tag>python</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/read-view/ rel=tag>read view</a><span class=tag-list-count>3</span><li class=tag-list-item><a class=tag-list-link href=/tags/redis/ rel=tag>redis</a><span class=tag-list-count>12</span><li class=tag-list-item><a class=tag-list-link href=/tags/scp/ rel=tag>scp</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/signal/ rel=tag>signal</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/sort/ rel=tag>sort</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/spark/ rel=tag>spark</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/ssh/ rel=tag>ssh</a><span class=tag-list-count>3</span><li class=tag-list-item><a class=tag-list-link href=/tags/stack/ rel=tag>stack</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/stream/ rel=tag>stream</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/string/ rel=tag>string</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/swoole/ rel=tag>swoole</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/top/ rel=tag>top</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/uname/ rel=tag>uname</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/unlock/ rel=tag>unlock</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/utf8/ rel=tag>utf8</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/utf8mb4/ rel=tag>utf8mb4</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/utf8mb4-0900-ai-ci/ rel=tag>utf8mb4_0900_ai_ci</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/utf8mb4-general-ci/ rel=tag>utf8mb4_general_ci</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/utf8mb4-unicode-ci/ rel=tag>utf8mb4_unicode_ci</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/value/ rel=tag>value</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/websocket/ rel=tag>websocket</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/windows/ rel=tag>windows</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/wsl/ rel=tag>wsl</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/zookeeper/ rel=tag>zookeeper</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/zsh/ rel=tag>zsh</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E4%B8%89%E9%98%B6%E6%AE%B5%E6%8F%90%E4%BA%A4/ rel=tag>三阶段提交</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E4%B8%8D%E5%8F%AF%E5%8F%98%E5%BC%95%E7%94%A8/ rel=tag>不可变引用</a><span class=tag-list-count>2</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E4%B8%9C%E4%BA%AC%E5%A5%A5%E8%BF%90%E4%BC%9A/ rel=tag>东京奥运会</a><span class=tag-list-count>2</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E4%B8%A4%E9%98%B6%E6%AE%B5%E6%8F%90%E4%BA%A4/ rel=tag>两阶段提交</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E4%B8%AD%E5%B1%B1%E8%B7%AF/ rel=tag>中山路</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E4%B8%AD%E5%BA%8F/ rel=tag>中序</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E4%B8%AD%E9%97%B4%E4%BB%B6/ rel=tag>中间件</a><span class=tag-list-count>4</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E4%B8%BE%E9%87%8D/ rel=tag>举重</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E4%B9%92%E4%B9%93%E7%90%83/ rel=tag>乒乓球</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E4%BA%8B%E5%8A%A1/ rel=tag>事务</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E4%BA%8C%E5%8F%89%E6%A0%91/ rel=tag>二叉树</a><span class=tag-list-count>3</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E4%BA%92%E6%96%A5%E9%94%81/ rel=tag>互斥锁</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E4%BB%A3%E7%A0%81%E9%A2%98%E8%A7%A3/ rel=tag>代码题解</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E4%BF%AE%E7%94%B5%E8%84%91%E7%9A%84/ rel=tag>修电脑的</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%81%8F%E5%90%91%E9%94%81/ rel=tag>偏向锁</a><span class=tag-list-count>2</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%81%A5%E5%BA%B7%E7%A0%81/ rel=tag>健康码</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%85%AC%E4%BA%A4/ rel=tag>公交</a><span class=tag-list-count>3</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%85%AC%E4%BA%A4%E8%BD%A6/ rel=tag>公交车</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%86%85%E5%AD%98%E5%88%86%E5%B8%83/ rel=tag>内存分布</a><span class=tag-list-count>3</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%86%85%E5%AD%98%E6%B3%84%E6%BC%8F/ rel=tag>内存泄漏</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%87%86%E5%A4%87/ rel=tag>准备</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%87%8F%E8%82%A5/ rel=tag>减肥</a><span class=tag-list-count>7</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%88%86%E5%B8%83%E5%BC%8F%E4%BA%8B%E5%8A%A1/ rel=tag>分布式事务</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81/ rel=tag>分布式锁</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%88%87%E7%89%87/ rel=tag>切片</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%88%9D%E5%A7%8B%E5%8C%96/ rel=tag>初始化</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%89%8A%E5%B3%B0%E5%A1%AB%E8%B0%B7/ rel=tag>削峰填谷</a><span class=tag-list-count>4</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%89%8D%E5%BA%8F/ rel=tag>前序</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%8A%A0%E5%A1%9E/ rel=tag>加塞</a><span class=tag-list-count>3</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%8A%A0%E8%BD%BD/ rel=tag>加载</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%8D%95%E4%BE%8B/ rel=tag>单例</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%8D%9A%E5%AE%A2%EF%BC%8C%E6%96%87%E7%AB%A0/ rel=tag>博客,文章</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%8E%A6%E9%97%A8/ rel=tag>厦门</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%8F%8C%E4%BA%B2%E5%A7%94%E6%B4%BE/ rel=tag>双亲委派</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%8F%91%E8%A1%8C%E7%89%88/ rel=tag>发行版</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%8F%A3%E7%BD%A9/ rel=tag>口罩</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%8F%AF%E5%8F%98%E5%BC%95%E7%94%A8/ rel=tag>可变引用</a><span class=tag-list-count>2</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%90%90%E6%A7%BD/ rel=tag>吐槽</a><span class=tag-list-count>2</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%9B%A4%E7%89%A9%E8%B5%84/ rel=tag>囤物资</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6/ rel=tag>垃圾回收</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%9F%BA%E7%A1%80%E8%AE%BE%E6%96%BD/ rel=tag>基础设施</a><span class=tag-list-count>2</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%A4%A7%E6%89%AB%E9%99%A4/ rel=tag>大扫除</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%AD%97%E7%AC%A6%E9%9B%86/ rel=tag>字符集</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%AE%89%E5%85%A8/ rel=tag>安全</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%AE%B9%E9%94%99%E6%9C%BA%E5%88%B6/ rel=tag>容错机制</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%AF%84%E7%94%9F%E8%99%AB/ rel=tag>寄生虫</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%B0%84%E5%87%BB/ rel=tag>射击</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%B0%8F%E6%8A%80%E5%B7%A7/ rel=tag>小技巧</a><span class=tag-list-count>6</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%B1%80%E5%8F%A3%E8%A1%97/ rel=tag>局口街</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%B8%83%E9%9A%86%E8%BF%87%E6%BB%A4%E5%99%A8/ rel=tag>布隆过滤器</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%B9%B2%E6%B4%BB/ rel=tag>干活</a><span class=tag-list-count>6</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%B9%B4%E4%B8%AD%E6%80%BB%E7%BB%93/ rel=tag>年中总结</a><span class=tag-list-count>2</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%B9%B4%E7%BB%88%E6%80%BB%E7%BB%93/ rel=tag>年终总结</a><span class=tag-list-count>4</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%B9%B6%E5%8F%91/ rel=tag>并发</a><span class=tag-list-count>2</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%B9%B8%E7%A6%8F%E4%BA%86%E5%90%97/ rel=tag>幸福了吗</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%B9%BB%E8%AF%BB/ rel=tag>幻读</a><span class=tag-list-count>2</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%BA%94%E7%94%A8/ rel=tag>应用</a><span class=tag-list-count>2</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%BC%80%E8%BD%A6/ rel=tag>开车</a><span class=tag-list-count>3</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%BC%B1%E5%BC%95%E7%94%A8/ rel=tag>弱引用</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%BD%B1%E8%AF%84/ rel=tag>影评</a><span class=tag-list-count>2</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E6%89%80%E6%9C%89%E6%9D%83/ rel=tag>所有权</a><span class=tag-list-count>3</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E6%89%93%E5%8D%A1/ rel=tag>打卡</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E6%89%B6%E6%A2%AF/ rel=tag>扶梯</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E6%8A%80%E6%9C%AF/ rel=tag>技术</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E6%8B%96%E6%9B%B4/ rel=tag>拖更</a><span class=tag-list-count>2</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E6%8D%A2%E8%BD%A6%E7%89%8C/ rel=tag>换车牌</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E6%8E%92%E5%BA%8F/ rel=tag>排序</a><span class=tag-list-count>2</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E6%8E%A5%E9%9B%A8%E6%B0%B4/ rel=tag>接雨水</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E6%95%B0%E6%8D%AE%E6%BA%90%E5%8A%A8%E6%80%81%E5%88%87%E6%8D%A2/ rel=tag>数据源动态切换</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/ rel=tag>数据结构</a><span class=tag-list-count>11</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E6%96%B0%E8%AF%AD%E8%A8%80/ rel=tag>新语言</a><span class=tag-list-count>3</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E6%97%85%E6%B8%B8/ rel=tag>旅游</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E6%97%A5%E5%BF%97/ rel=tag>日志</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E6%9B%BE%E5%8E%9D%E5%9E%B5/ rel=tag>曾厝垵</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E6%9C%80%E5%B0%8F%E6%A0%88/ rel=tag>最小栈</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E6%9D%80%E4%BA%BA%E8%AF%9B%E5%BF%83/ rel=tag>杀人诛心</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E6%9D%AD%E5%B7%9E/ rel=tag>杭州</a><span class=tag-list-count>4</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E6%A0%87%E8%AE%B0%E6%95%B4%E7%90%86/ rel=tag>标记整理</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E6%A4%8D%E7%89%A9%E5%9B%AD/ rel=tag>植物园</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E6%B2%99%E8%8C%B6%E9%9D%A2/ rel=tag>沙茶面</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E6%B3%A8%E8%A7%A3/ rel=tag>注解</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E6%B5%B7%E8%9B%8E%E7%85%8E/ rel=tag>海蛎煎</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97/ rel=tag>消息队列</a><span class=tag-list-count>9</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E6%B7%98%E6%B1%B0%E7%AD%96%E7%95%A5/ rel=tag>淘汰策略</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0/ rel=tag>深度学习</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E6%BA%90%E7%A0%81/ rel=tag>源码</a><span class=tag-list-count>11</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/ rel=tag>源码解析</a><span class=tag-list-count>3</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E7%94%9F%E6%B4%BB/ rel=tag>生活</a><span class=tag-list-count>42</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E7%94%B5%E7%93%B6%E8%BD%A6/ rel=tag>电瓶车</a><span class=tag-list-count>2</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E7%96%AB%E6%83%85/ rel=tag>疫情</a><span class=tag-list-count>2</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E7%9C%8B%E4%B9%A6/ rel=tag>看书</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E7%9C%8B%E5%89%A7/ rel=tag>看剧</a><span class=tag-list-count>3</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E7%9F%A9%E9%98%B5/ rel=tag>矩阵</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E7%AB%AF%E5%8F%A3%E8%BD%AC%E5%8F%91/ rel=tag>端口转发</a><span class=tag-list-count>3</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E7%B1%BB%E5%8A%A0%E8%BD%BD/ rel=tag>类加载</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E7%B3%9F%E5%BF%83%E4%BA%8B/ rel=tag>糟心事</a><span class=tag-list-count>5</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E7%B4%A2%E5%BC%95/ rel=tag>索引</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E7%BA%BF%E7%A8%8B%E6%B1%A0/ rel=tag>线程池</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E7%BC%93%E5%AD%98/ rel=tag>缓存</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E7%BC%93%E5%AD%98%E5%87%BB%E7%A9%BF/ rel=tag>缓存击穿</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E7%BC%93%E5%AD%98%E7%A9%BF%E9%80%8F/ rel=tag>缓存穿透</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E7%BC%93%E5%AD%98%E9%9B%AA%E5%B4%A9/ rel=tag>缓存雪崩</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E7%BC%96%E7%A0%81/ rel=tag>编码</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E7%BE%8E%E5%9B%BD/ rel=tag>美国</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E8%80%81%E7%94%B5%E8%84%91/ rel=tag>老电脑</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E8%87%AA%E5%8A%A8%E8%A3%85%E9%85%8D/ rel=tag>自动装配</a><span class=tag-list-count>2</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E8%87%AA%E6%97%8B/ rel=tag>自旋</a><span class=tag-list-count>2</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E8%87%AA%E9%80%82%E5%BA%94%E6%8B%93%E5%B1%95/ rel=tag>自适应拓展</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E8%A3%85%E7%94%B5%E8%84%91/ rel=tag>装电脑</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E8%A7%84%E5%88%99/ rel=tag>规则</a><span class=tag-list-count>4</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E8%A7%A3%E6%9E%90/ rel=tag>解析</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/ rel=tag>设计模式</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E8%AF%BB%E4%B9%A6/ rel=tag>读书</a><span class=tag-list-count>2</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E8%AF%BB%E5%90%8E%E6%84%9F/ rel=tag>读后感</a><span class=tag-list-count>4</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1/ rel=tag>负载均衡</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E8%B6%B3%E7%90%83/ rel=tag>足球</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E8%B7%91%E6%AD%A5/ rel=tag>跑步</a><span class=tag-list-count>7</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E8%B7%AF%E6%94%BF%E8%A7%84%E5%88%92/ rel=tag>路政规划</a><span class=tag-list-count>2</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E8%B7%AF%E7%94%B1%E5%99%A8/ rel=tag>路由器</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E8%B7%B3%E6%B0%B4/ rel=tag>跳水</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E8%B8%A9%E8%B8%8F/ rel=tag>踩踏</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E8%BD%AC%E4%B9%89/ rel=tag>转义</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E8%BD%BB%E9%87%8F%E7%BA%A7%E9%94%81/ rel=tag>轻量级锁</a><span class=tag-list-count>2</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E8%BF%87%E6%9C%9F%E7%AD%96%E7%95%A5/ rel=tag>过期策略</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E8%BF%90%E5%8A%A8/ rel=tag>运动</a><span class=tag-list-count>9</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E8%BF%9C%E7%A8%8B%E5%8A%9E%E5%85%AC/ rel=tag>远程办公</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E9%80%92%E5%BD%92/ rel=tag>递归</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E9%87%8D%E9%87%8F%E7%BA%A7%E9%94%81/ rel=tag>重量级锁</a><span class=tag-list-count>2</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E9%93%BE%E6%8E%A5/ rel=tag>链接</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E9%A2%98%E8%A7%A3/ rel=tag>题解</a><span class=tag-list-count>24</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E9%A9%AC%E6%88%8F%E5%9B%A2/ rel=tag>马戏团</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E9%AA%8C%E8%AF%81/ rel=tag>验证</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E9%AA%91%E8%BD%A6/ rel=tag>骑车</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E9%AB%98%E9%80%9F/ rel=tag>高速</a><span class=tag-list-count>1</span><li class=tag-list-item><a class=tag-list-link href=/tags/%E9%BC%93%E6%B5%AA%E5%B1%BF/ rel=tag>鼓浪屿</a><span class=tag-list-count>1</span></ul></canvas></div></div></div></div></div><div class="sidebar-inner sidebar-blogroll"><div class="links-of-blogroll animated"><div class=links-of-blogroll-title><i class="fa fa-globe fa-fw"></i> 链接</div><ul class=links-of-blogroll-list><li class=links-of-blogroll-item><a href=https://covermusic.cn/ rel=noopener target=_blank title=https://covermusic.cn>69伙伴</a></ul></div></div></aside></div><div class="main-inner index posts-expand"><div class=post-block><article class=post-content itemscope itemtype=http://schema.org/Article><link href=https://nicksxs.me/2021/03/14/Leetcode-121-%E4%B9%B0%E5%8D%96%E8%82%A1%E7%A5%A8%E7%9A%84%E6%9C%80%E4%BD%B3%E6%97%B6%E6%9C%BA-Best-Time-to-Buy-and-Sell-Stock-%E9%A2%98%E8%A7%A3%E5%88%86%E6%9E%90/ itemprop=mainEntityOfPage><span hidden itemprop=author itemscope itemtype=http://schema.org/Person><meta content=/uploads/avatar.jpg itemprop=image><meta content=Nicksxs itemprop=name></span><span hidden itemprop=publisher itemscope itemtype=http://schema.org/Organization><meta content="Nicksxs's Blog" itemprop=name><meta content="learn from zero,技术博客,Nicksxs,史学森" itemprop=description></span><span hidden itemprop=post itemscope itemtype=http://schema.org/CreativeWork><meta content="undefined | Nicksxs's Blog" itemprop=name><meta itemprop=description></span><header class=post-header><h2 itemprop="name headline" class=post-title><a class=post-title-link href=/2021/03/14/Leetcode-121-%E4%B9%B0%E5%8D%96%E8%82%A1%E7%A5%A8%E7%9A%84%E6%9C%80%E4%BD%B3%E6%97%B6%E6%9C%BA-Best-Time-to-Buy-and-Sell-Stock-%E9%A2%98%E8%A7%A3%E5%88%86%E6%9E%90/ itemprop=url>Leetcode 121 买卖股票的最佳时机(Best Time to Buy and Sell Stock) 题解分析</a></h2><div class=post-meta-container><div class=post-meta><span class=post-meta-item><span class=post-meta-item-icon><i class="far fa-calendar"></i> </span><span class=post-meta-item-text>发表于</span> <time itemprop="dateCreated datePublished" title="创建时间:2021-03-14 22:34:30" datetime=2021-03-14T22:34:30+08:00>2021-03-14</time> </span><span class=post-meta-item><span class=post-meta-item-icon><i class="far fa-folder"></i> </span><span class=post-meta-item-text>分类于</span> <span itemprop=about itemscope itemtype=http://schema.org/Thing><a href=/categories/Java/ itemprop=url rel=index><span itemprop=name>Java</span></a> </span><span itemprop=about itemscope itemtype=http://schema.org/Thing><a href=/categories/leetcode/ itemprop=url rel=index><span itemprop=name>leetcode</span></a> </span><span itemprop=about itemscope itemtype=http://schema.org/Thing><a href=/categories/leetcode/java/ itemprop=url rel=index><span itemprop=name>java</span></a> </span><span itemprop=about itemscope itemtype=http://schema.org/Thing><a href=/categories/DP/ itemprop=url rel=index><span itemprop=name>DP</span></a> </span><span itemprop=about itemscope itemtype=http://schema.org/Thing><a href=/categories/leetcode/java/DP/ itemprop=url rel=index><span itemprop=name>DP</span></a> </span></span><span class="post-meta-item leancloud_visitors" data-flag-title="Leetcode 121 买卖股票的最佳时机(Best Time to Buy and Sell Stock) 题解分析" id=/2021/03/14/Leetcode-121-%E4%B9%B0%E5%8D%96%E8%82%A1%E7%A5%A8%E7%9A%84%E6%9C%80%E4%BD%B3%E6%97%B6%E6%9C%BA-Best-Time-to-Buy-and-Sell-Stock-%E9%A2%98%E8%A7%A3%E5%88%86%E6%9E%90/ title=阅读次数><span class=post-meta-item-icon><i class="far fa-eye"></i> </span><span class=post-meta-item-text>阅读次数:</span> <span class=leancloud-visitors-count></span> </span><span class=post-meta-item><span class=post-meta-item-icon><i class="far fa-comment"></i> </span><span class=post-meta-item-text>Disqus:</span> <a href=/2021/03/14/Leetcode-121-%E4%B9%B0%E5%8D%96%E8%82%A1%E7%A5%A8%E7%9A%84%E6%9C%80%E4%BD%B3%E6%97%B6%E6%9C%BA-Best-Time-to-Buy-and-Sell-Stock-%E9%A2%98%E8%A7%A3%E5%88%86%E6%9E%90/#disqus_thread itemprop=discussionUrl title=disqus><span class="post-comments-count disqus-comment-count" data-disqus-identifier=2021/03/14/Leetcode-121-买卖股票的最佳时机-Best-Time-to-Buy-and-Sell-Stock-题解分析/ itemprop=commentCount></span></a></span></div></div></header><div class=post-body itemprop=articleBody><h3 id=题目介绍><a class=headerlink href=#题目介绍 title=题目介绍></a>题目介绍</h3><p>You are given an array <code>prices</code> where <code>prices[i]</code> is the price of a given stock on the i<sup>th</sup> day.<p>You want to maximize your profit by choosing a <strong>single day</strong> to buy one stock and choosing a <strong>different day in the future</strong> to sell that stock.<p>Return the maximum profit you can achieve from this transaction. If you cannot achieve any profit, return <code>0</code>.<p>给定一个数组 <code>prices</code> ,它的第 <code>i</code> 个元素 <code>prices[i]</code> 表示一支给定股票第 <code>i</code> 天的价格。<p>你只能选择 <strong>某一天</strong> 买入这只股票,并选择在 <strong>未来的某一个不同的日子</strong> 卖出该股票。设计一个算法来计算你所能获取的最大利润。<p>返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 <code>0</code><h3 id=简单分析><a class=headerlink href=#简单分析 title=简单分析></a>简单分析</h3><p>其实这个跟二叉树的最长路径和有点类似,需要找到整体的最大收益,但是在迭代过程中需要一个当前的值<pre class="line-numbers language-java" data-language=java><code class=language-java><span class="token keyword">int</span> maxSofar <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">int</span> <span class="token function">maxProfit</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span> prices<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>prices<span class="token punctuation">.</span>length <span class="token operator"><=</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">int</span> maxIn <span class="token operator">=</span> prices<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> maxOut <span class="token operator">=</span> prices<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> i <span class="token operator"><</span> prices<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>maxIn <span class="token operator">></span> prices<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// 当循环当前值小于之前的买入值时就当成买入值,同时卖出也要更新</span>
maxIn <span class="token operator">=</span> prices<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span>
maxOut <span class="token operator">=</span> prices<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>prices<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">></span> maxOut<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// 表示一个可卖出点,即比买入值高时</span>
maxOut <span class="token operator">=</span> prices<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token comment">// 需要设置一个历史值</span>
maxSofar <span class="token operator">=</span> <span class="token class-name">Math</span><span class="token punctuation">.</span><span class="token function">max</span><span class="token punctuation">(</span>maxSofar<span class="token punctuation">,</span> maxOut <span class="token operator">-</span> maxIn<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> maxSofar<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span aria-hidden=true class=line-numbers-rows><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id=总结下><a class=headerlink href=#总结下 title=总结下></a>总结下</h3><p>一开始看到 easy 就觉得是很简单,就没有 maxSofar ,但是一提交就出现问题了<br>对于<code>[2, 4, 1]</code>这种就会变成 0,所以还是需要一个历史值来存放历史最大值,这题有点动态规划的意思</div><footer class=post-footer><div class=post-eof></div></footer></article></div><div class=post-block><article class=post-content itemscope itemtype=http://schema.org/Article><link href=https://nicksxs.me/2021/03/07/%E3%80%8A%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6%E7%AE%97%E6%B3%95%E6%89%8B%E5%86%8C%E8%AF%BB%E4%B9%A6%E3%80%8B%E7%AC%94%E8%AE%B0%E4%B9%8B%E6%95%B4%E7%90%86%E7%AE%97%E6%B3%95/ itemprop=mainEntityOfPage><span hidden itemprop=author itemscope itemtype=http://schema.org/Person><meta content=/uploads/avatar.jpg itemprop=image><meta content=Nicksxs itemprop=name></span><span hidden itemprop=publisher itemscope itemtype=http://schema.org/Organization><meta content="Nicksxs's Blog" itemprop=name><meta content="learn from zero,技术博客,Nicksxs,史学森" itemprop=description></span><span hidden itemprop=post itemscope itemtype=http://schema.org/CreativeWork><meta content="undefined | Nicksxs's Blog" itemprop=name><meta itemprop=description></span><header class=post-header><h2 itemprop="name headline" class=post-title><a class=post-title-link href=/2021/03/07/%E3%80%8A%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6%E7%AE%97%E6%B3%95%E6%89%8B%E5%86%8C%E8%AF%BB%E4%B9%A6%E3%80%8B%E7%AC%94%E8%AE%B0%E4%B9%8B%E6%95%B4%E7%90%86%E7%AE%97%E6%B3%95/ itemprop=url>《垃圾回收算法手册读书》笔记之整理算法</a></h2><div class=post-meta-container><div class=post-meta><span class=post-meta-item><span class=post-meta-item-icon><i class="far fa-calendar"></i> </span><span class=post-meta-item-text>发表于</span> <time itemprop="dateCreated datePublished" title="创建时间:2021-03-07 20:37:06" datetime=2021-03-07T20:37:06+08:00>2021-03-07</time> </span><span class=post-meta-item><span class=post-meta-item-icon><i class="far fa-calendar-check"></i> </span><span class=post-meta-item-text>更新于</span> <time title="修改时间:2022-06-11 22:45:11" datetime=2022-06-11T22:45:11+08:00 itemprop=dateModified>2022-06-11</time> </span><span class=post-meta-item><span class=post-meta-item-icon><i class="far fa-folder"></i> </span><span class=post-meta-item-text>分类于</span> <span itemprop=about itemscope itemtype=http://schema.org/Thing><a href=/categories/Java/ itemprop=url rel=index><span itemprop=name>Java</span></a> </span><span itemprop=about itemscope itemtype=http://schema.org/Thing><a href=/categories/Java/gc/ itemprop=url rel=index><span itemprop=name>gc</span></a> </span><span itemprop=about itemscope itemtype=http://schema.org/Thing><a href=/categories/Java/gc/jvm/ itemprop=url rel=index><span itemprop=name>jvm</span></a> </span></span><span class="post-meta-item leancloud_visitors" data-flag-title=《垃圾回收算法手册读书》笔记之整理算法 id=/2021/03/07/%E3%80%8A%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6%E7%AE%97%E6%B3%95%E6%89%8B%E5%86%8C%E8%AF%BB%E4%B9%A6%E3%80%8B%E7%AC%94%E8%AE%B0%E4%B9%8B%E6%95%B4%E7%90%86%E7%AE%97%E6%B3%95/ title=阅读次数><span class=post-meta-item-icon><i class="far fa-eye"></i> </span><span class=post-meta-item-text>阅读次数:</span> <span class=leancloud-visitors-count></span> </span><span class=post-meta-item><span class=post-meta-item-icon><i class="far fa-comment"></i> </span><span class=post-meta-item-text>Disqus:</span> <a href=/2021/03/07/%E3%80%8A%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6%E7%AE%97%E6%B3%95%E6%89%8B%E5%86%8C%E8%AF%BB%E4%B9%A6%E3%80%8B%E7%AC%94%E8%AE%B0%E4%B9%8B%E6%95%B4%E7%90%86%E7%AE%97%E6%B3%95/#disqus_thread itemprop=discussionUrl title=disqus><span class="post-comments-count disqus-comment-count" data-disqus-identifier=2021/03/07/《垃圾回收算法手册读书》笔记之整理算法/ itemprop=commentCount></span></a></span></div></div></header><div class=post-body itemprop=articleBody><p>最近看了下这本垃圾回收算法手册,看到了第三章的标记-整理回收算法,做个简单的读书笔记<h3 id=双指针整理算法><a class=headerlink href=#双指针整理算法 title=双指针整理算法></a>双指针整理算法</h3><p>对于一块待整理区域,通过两个指针,free 在区域的起始端,scan 指针在区域的末端,free 指针从前往后知道找到空闲区域,scan 从后往前一直找到存活对象,当 free 指针未与 scan 指针交叉时,会给 scan 位置的对象特定位置标记上 free 的地址,即将要转移的地址,不过这里有个限制,这种整理算法一般会用于对象大小统一的情况,否则 free 指针扫描时还需要匹配scan 指针扫描到的存活对象的大小。<br><img data-src=https://img.nicksxs.com/uPic/yLQlgj.png><h3 id=Lisp-2-整理算法><a title="Lisp 2 整理算法" class=headerlink href=#Lisp-2-整理算法></a>Lisp 2 整理算法</h3><p>需要三次完整遍历堆区域<br>第一遍是遍历后将计算出所有对象的最终地址(转发地址)<br>第二遍是使用转发地址更新赋值器线程根以及被标记对象中的引用,该操作将确保它们指向对象的新位置<br>第三次遍历是relocate最终将存活对象移动到其新的目标位置<h3 id=引线整理算法><a class=headerlink href=#引线整理算法 title=引线整理算法></a>引线整理算法</h3><p>这个真的长见识了,<br><img data-src=https://img.nicksxs.com/uPic/6yeA7n.png><br>可以看到,原来是 A,B,C 对象引用了 N,这里会在第一次遍历的时候把这种引用反过来,让 N 的对象头部保存下 A 的地址,表示这类引用,然后在遍历到 B 的时候在链起来,到最后就会把所有引用了 N 对象的所有对象通过引线链起来,在第二次遍历的时候就把更新A,B,C 对象引用的 N 地址,并且移动 N 对象<h3 id=单次遍历算法><a class=headerlink href=#单次遍历算法 title=单次遍历算法></a>单次遍历算法</h3><p>这个一直提到过位图的实现方式,<br><img data-src=https://img.nicksxs.com/uPic/Jqtuzu.png><br>可以看到在第一步会先通过位图标记,标记的方式是位图的每一位对应的堆内存的一个字(这里可能指的是 byte 吧),然后将一个存活对象的内存区域的第一个字跟最后一个字标记,这里如果在通过普通的方式就还需要一个地方在存转发地址,但是因为具体的位置可以通过位图算出来,也就不需要额外记录了</div><footer class=post-footer><div class=post-eof></div></footer></article></div><div class=post-block><article class=post-content itemscope itemtype=http://schema.org/Article><link href=https://nicksxs.me/2021/02/28/%E9%97%B2%E8%81%8A%E4%B8%8B%E4%B9%98%E5%85%AC%E4%BA%A4%E7%9A%84%E7%94%A8%E6%88%B7%E4%BD%93%E9%AA%8C/ itemprop=mainEntityOfPage><span hidden itemprop=author itemscope itemtype=http://schema.org/Person><meta content=/uploads/avatar.jpg itemprop=image><meta content=Nicksxs itemprop=name></span><span hidden itemprop=publisher itemscope itemtype=http://schema.org/Organization><meta content="Nicksxs's Blog" itemprop=name><meta content="learn from zero,技术博客,Nicksxs,史学森" itemprop=description></span><span hidden itemprop=post itemscope itemtype=http://schema.org/CreativeWork><meta content="undefined | Nicksxs's Blog" itemprop=name><meta itemprop=description></span><header class=post-header><h2 itemprop="name headline" class=post-title><a class=post-title-link href=/2021/02/28/%E9%97%B2%E8%81%8A%E4%B8%8B%E4%B9%98%E5%85%AC%E4%BA%A4%E7%9A%84%E7%94%A8%E6%88%B7%E4%BD%93%E9%AA%8C/ itemprop=url>闲聊下乘公交的用户体验</a></h2><div class=post-meta-container><div class=post-meta><span class=post-meta-item><span class=post-meta-item-icon><i class="far fa-calendar"></i> </span><span class=post-meta-item-text>发表于</span> <time itemprop="dateCreated datePublished" title="创建时间:2021-02-28 21:56:42" datetime=2021-02-28T21:56:42+08:00>2021-02-28</time> </span><span class=post-meta-item><span class=post-meta-item-icon><i class="far fa-folder"></i> </span><span class=post-meta-item-text>分类于</span> <span itemprop=about itemscope itemtype=http://schema.org/Thing><a href=/categories/%E7%94%9F%E6%B4%BB/ itemprop=url rel=index><span itemprop=name>生活</span></a> </span><span itemprop=about itemscope itemtype=http://schema.org/Thing><a href=/categories/%E7%94%9F%E6%B4%BB/%E5%85%AC%E4%BA%A4/ itemprop=url rel=index><span itemprop=name>公交</span></a> </span></span><span class="post-meta-item leancloud_visitors" data-flag-title=闲聊下乘公交的用户体验 id=/2021/02/28/%E9%97%B2%E8%81%8A%E4%B8%8B%E4%B9%98%E5%85%AC%E4%BA%A4%E7%9A%84%E7%94%A8%E6%88%B7%E4%BD%93%E9%AA%8C/ title=阅读次数><span class=post-meta-item-icon><i class="far fa-eye"></i> </span><span class=post-meta-item-text>阅读次数:</span> <span class=leancloud-visitors-count></span> </span><span class=post-meta-item><span class=post-meta-item-icon><i class="far fa-comment"></i> </span><span class=post-meta-item-text>Disqus:</span> <a href=/2021/02/28/%E9%97%B2%E8%81%8A%E4%B8%8B%E4%B9%98%E5%85%AC%E4%BA%A4%E7%9A%84%E7%94%A8%E6%88%B7%E4%BD%93%E9%AA%8C/#disqus_thread itemprop=discussionUrl title=disqus><span class="post-comments-count disqus-comment-count" data-disqus-identifier=2021/02/28/闲聊下乘公交的用户体验/ itemprop=commentCount></span></a></span></div></div></header><div class=post-body itemprop=articleBody><p>新年开工开车来杭州,因为没有车位加限行今天来就没开车来了,从东站做公交回住的地方,这班神奇的车我之前也吐槽过了,有神奇的乘客和神奇的司机,因为基本上这班车是从我毕业就开始乘了,所以也算是比较熟悉了,以前总体感觉不太好的是乘坐时间太长了,不过这个也不能怪车,是我自己住得远(离东站),后来住到了现在的地方,也算是直达,并且 LD 比较喜欢直达的,不爱更快却要换乘的地铁,所以坐的频率比较高,也说过前面那些比较气人的乘客,自己不好好戴口罩,反而联合一起上车的乘客诽谤司机,说他要吃人了要打人了,也正是这个司机比较有意思,上车就让戴好口罩,还给大家讲,哪里哪里又有疫情了,我觉得其实这个司机还是不错的,特殊时期,对于这种公共交通,这样的确是比较负责任的做法,只是说话方式,语气这个因人而异,他也不是来伺候人的,而且这么一大车人,说了一遍不行,再说一遍,三遍以上了,嗓门大一点也属于正常的人的行为。<br>还是说回今天要说的,今天这位司机我看着跟前面说的那位有点像,因为上车的时候比较暗没看清脸,主要原因是这位司机开车比较猛,比较急,然后车上因为这个时间点,比较多大学开学来的学生,拎着个行李箱,一开始是前面已经都站满了人,后面还有很多空位,因为后面没地方放行李箱,就因为这样前面站着的有几个就在说司机开慢点,结果司机貌似也没听进去,还是我行我素,过了会又有人说司机开稳一点,就在这个人说完没一会,停在红绿灯路口的车里,就有人问有没有垃圾桶,接着又让司机开门,说晕车太严重了,要下车,司机开了门,我望出去两个妹子下了车,好像在路边草丛吐了,前面开门下车的时候就有人说她们第一次来杭州,可能有点责怪司机开的不稳,也影响了杭州交通给新来杭州的人的感受,说完了事情经过,其实我有蛮多感触,对于杭州公交司机,我大概是大一来了没多久,陪室友去文三路买电脑就晕车,下车的时候在公交车站吐了,可能是从大学开始缺乏锻炼,又饮食不规律,更加容易晕车,大部分晕车我觉得都是我自己的原因,有时候是上车前吃太多了,或者早上起太早,没睡好,没吃东西,反正自己也是挺多原因的,说到司机的原因的话,我觉得可能这班车还算好的,最让我难受的还是上下班高峰的时候,因为经过的那条路是比较重要的主干道,路比较老比较窄,并且还有很多人行道,所以经常一脚油门连带着一脚刹车,真的很难受,这种算是我觉得真的是公交体验比较差的一点,但是这一点呢也不能完全怪公交司机,杭州的路政规划是很垃圾,没看错,是垃圾,所以总体结论是公交还行,主要是路政规划就是垃圾,包括这条主干道这么多人行道,并且两边都是老小区,老年人在上班高峰可能要买菜送娃或者其他事情,在通畅的情况下可能只需要六分钟的路程,有时候因为各种原因,半小时都开不完,扯开去一点,杭州的路,核心的高速说封就封,本来是高架可以直接通到城西,结果没造,到了路本已经很拥挤的时候开始来造隧道,各种破坏,隧道接高架的地方,无尽的加塞,对于我这样的小白司机来说真的是太恶心了,所以我一直想说的就是杭州这个地方房价领先基础设施十年,地铁,高架,高速通通不行,地面道路就更不行了。<br>总结下,其实杭州的真正的公交体验差,应该还是路造成的,对于前面的那两位妹子来说,有可能是她们来自于公交司机都是开的特别稳,并且路况也很好的地方,也或者是我被虐习惯了🤦‍♂️</div><footer class=post-footer><div class=post-eof></div></footer></article></div><div class=post-block><article class=post-content itemscope itemtype=http://schema.org/Article><link href=https://nicksxs.me/2021/02/21/AQS-%E4%B9%8B-Condition-%E6%B5%85%E6%9E%90%E7%AC%94%E8%AE%B0/ itemprop=mainEntityOfPage><span hidden itemprop=author itemscope itemtype=http://schema.org/Person><meta content=/uploads/avatar.jpg itemprop=image><meta content=Nicksxs itemprop=name></span><span hidden itemprop=publisher itemscope itemtype=http://schema.org/Organization><meta content="Nicksxs's Blog" itemprop=name><meta content="learn from zero,技术博客,Nicksxs,史学森" itemprop=description></span><span hidden itemprop=post itemscope itemtype=http://schema.org/CreativeWork><meta content="undefined | Nicksxs's Blog" itemprop=name><meta itemprop=description></span><header class=post-header><h2 itemprop="name headline" class=post-title><a class=post-title-link href=/2021/02/21/AQS-%E4%B9%8B-Condition-%E6%B5%85%E6%9E%90%E7%AC%94%E8%AE%B0/ itemprop=url>AQS篇二 之 Condition 浅析笔记</a></h2><div class=post-meta-container><div class=post-meta><span class=post-meta-item><span class=post-meta-item-icon><i class="far fa-calendar"></i> </span><span class=post-meta-item-text>发表于</span> <time itemprop="dateCreated datePublished" title="创建时间:2021-02-21 21:27:06" datetime=2021-02-21T21:27:06+08:00>2021-02-21</time> </span><span class=post-meta-item><span class=post-meta-item-icon><i class="far fa-calendar-check"></i> </span><span class=post-meta-item-text>更新于</span> <time title="修改时间:2022-06-11 22:45:11" datetime=2022-06-11T22:45:11+08:00 itemprop=dateModified>2022-06-11</time> </span><span class=post-meta-item><span class=post-meta-item-icon><i class="far fa-folder"></i> </span><span class=post-meta-item-text>分类于</span> <span itemprop=about itemscope itemtype=http://schema.org/Thing><a href=/categories/Java/ itemprop=url rel=index><span itemprop=name>Java</span></a> </span><span itemprop=about itemscope itemtype=http://schema.org/Thing><a href=/categories/Java/%E5%B9%B6%E5%8F%91/ itemprop=url rel=index><span itemprop=name>并发</span></a> </span></span><span class="post-meta-item leancloud_visitors" data-flag-title="AQS篇二 之 Condition 浅析笔记" id=/2021/02/21/AQS-%E4%B9%8B-Condition-%E6%B5%85%E6%9E%90%E7%AC%94%E8%AE%B0/ title=阅读次数><span class=post-meta-item-icon><i class="far fa-eye"></i> </span><span class=post-meta-item-text>阅读次数:</span> <span class=leancloud-visitors-count></span> </span><span class=post-meta-item><span class=post-meta-item-icon><i class="far fa-comment"></i> </span><span class=post-meta-item-text>Disqus:</span> <a href=/2021/02/21/AQS-%E4%B9%8B-Condition-%E6%B5%85%E6%9E%90%E7%AC%94%E8%AE%B0/#disqus_thread itemprop=discussionUrl title=disqus><span class="post-comments-count disqus-comment-count" data-disqus-identifier=2021/02/21/AQS-之-Condition-浅析笔记/ itemprop=commentCount></span></a></span></div></div></header><div class=post-body itemprop=articleBody><p>Condition也是 AQS 中很重要的一块内容,可以先看段示例代码,这段代码应该来自于Doug Lea大大,可以在 javadoc 中的 <a href=https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/Condition.html rel=noopener target=_blank>condition</a> 部分找到,其实大大原来写过基于 <code>synchronized</code> 实现的,后面我也贴下代码<pre class="line-numbers language-java" data-language=java><code class=language-java><span class="token keyword">import</span> <span class="token import"><span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span>concurrent<span class="token punctuation">.</span>locks<span class="token punctuation">.</span></span><span class="token class-name">Condition</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span>concurrent<span class="token punctuation">.</span>locks<span class="token punctuation">.</span></span><span class="token class-name">Lock</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span>concurrent<span class="token punctuation">.</span>locks<span class="token punctuation">.</span></span><span class="token class-name">ReentrantLock</span></span><span class="token punctuation">;</span>
<span class="token keyword">class</span> <span class="token class-name">BoundedBuffer</span> <span class="token punctuation">{</span>
<span class="token keyword">final</span> <span class="token class-name">Lock</span> lock <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ReentrantLock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// condition 依赖于 lock 来产生</span>
<span class="token keyword">final</span> <span class="token class-name">Condition</span> notFull <span class="token operator">=</span> lock<span class="token punctuation">.</span><span class="token function">newCondition</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">final</span> <span class="token class-name">Condition</span> notEmpty <span class="token operator">=</span> lock<span class="token punctuation">.</span><span class="token function">newCondition</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 对象池子,put 跟 take 的就是这里的</span>
<span class="token keyword">final</span> <span class="token class-name">Object</span><span class="token punctuation">[</span><span class="token punctuation">]</span> items <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Object</span><span class="token punctuation">[</span><span class="token number">100</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> putptr<span class="token punctuation">,</span> takeptr<span class="token punctuation">,</span> count<span class="token punctuation">;</span>
<span class="token comment">// 生产</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">put</span><span class="token punctuation">(</span><span class="token class-name">Object</span> x<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">InterruptedException</span> <span class="token punctuation">{</span>
<span class="token comment">// 这里也说明了,需要先拥有锁</span>
lock<span class="token punctuation">.</span><span class="token function">lock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token keyword">while</span> <span class="token punctuation">(</span>count <span class="token operator">==</span> items<span class="token punctuation">.</span>length<span class="token punctuation">)</span>
notFull<span class="token punctuation">.</span><span class="token function">await</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 队列已满,等待,直到 not full 才能继续生产</span>
items<span class="token punctuation">[</span>putptr<span class="token punctuation">]</span> <span class="token operator">=</span> x<span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">++</span>putptr <span class="token operator">==</span> items<span class="token punctuation">.</span>length<span class="token punctuation">)</span> putptr <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token operator">++</span>count<span class="token punctuation">;</span>
notEmpty<span class="token punctuation">.</span><span class="token function">signal</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 生产成功,队列已经 not empty 了,发个通知出去</span>
<span class="token punctuation">}</span> <span class="token keyword">finally</span> <span class="token punctuation">{</span>
lock<span class="token punctuation">.</span><span class="token function">unlock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token comment">// 消费</span>
<span class="token keyword">public</span> <span class="token class-name">Object</span> <span class="token function">take</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">InterruptedException</span> <span class="token punctuation">{</span>
lock<span class="token punctuation">.</span><span class="token function">lock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token keyword">while</span> <span class="token punctuation">(</span>count <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span>
notEmpty<span class="token punctuation">.</span><span class="token function">await</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 队列为空,等待,直到队列 not empty,才能继续消费</span>
<span class="token class-name">Object</span> x <span class="token operator">=</span> items<span class="token punctuation">[</span>takeptr<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">++</span>takeptr <span class="token operator">==</span> items<span class="token punctuation">.</span>length<span class="token punctuation">)</span> takeptr <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token operator">--</span>count<span class="token punctuation">;</span>
notFull<span class="token punctuation">.</span><span class="token function">signal</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 被我消费掉一个,队列 not full 了,发个通知出去</span>
<span class="token keyword">return</span> x<span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">finally</span> <span class="token punctuation">{</span>
lock<span class="token punctuation">.</span><span class="token function">unlock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span aria-hidden=true class=line-numbers-rows><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>介绍下 Condition 的结构<pre class="line-numbers language-java" data-language=java><code class=language-java><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ConditionObject</span> <span class="token keyword">implements</span> <span class="token class-name">Condition</span><span class="token punctuation">,</span> <span class="token class-name"><span class="token namespace">java<span class="token punctuation">.</span>io<span class="token punctuation">.</span></span>Serializable</span> <span class="token punctuation">{</span>
<span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">long</span> serialVersionUID <span class="token operator">=</span> <span class="token number">1173984872572414699L</span><span class="token punctuation">;</span>
<span class="token comment">/** First node of condition queue. */</span>
<span class="token keyword">private</span> <span class="token keyword">transient</span> <span class="token class-name">Node</span> firstWaiter<span class="token punctuation">;</span>
<span class="token comment">/** Last node of condition queue. */</span>
<span class="token keyword">private</span> <span class="token keyword">transient</span> <span class="token class-name">Node</span> lastWaiter<span class="token punctuation">;</span><span aria-hidden=true class=line-numbers-rows><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>主要的就这么点,而且也复用了 AQS 阻塞队列或者大大叫 <code>lock queue</code>中同样的 Node 节点,只不过它没有使用其中的双向队列,也就是prev 和 next,而是在 Node 中的 nextWaiter,所以只是个单向的队列,没使用 next 其实还有个用处,后面会提到,看下结构的示意图<br><img data-src=https://img.nicksxs.com/uPic/Ss9oFX.png><br>然后主要是看两个方法,<code>await</code><code>signal</code>,<br>先来看下 await<pre class="line-numbers language-java" data-language=java><code class=language-java><span class="token comment">/**
* Implements interruptible condition wait.
* &LTol>
* &LTli> If current thread is interrupted, throw InterruptedException.
* &LTli> Save lock state returned by {@link #getState}.
* &LTli> Invoke {@link #release} with saved state as argument,
* throwing IllegalMonitorStateException if it fails.
* &LTli> Block until signalled or interrupted.
* &LTli> Reacquire by invoking specialized version of
* {@link #acquire} with saved state as argument.
* &LTli> If interrupted while blocked in step 4, throw InterruptedException.
* &LT/ol>
*/</span>
<span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">void</span> <span class="token function">await</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">InterruptedException</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">interrupted</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">InterruptedException</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 将当前节点包装成一个 condition waiter node 节点</span>
<span class="token class-name">Node</span> node <span class="token operator">=</span> <span class="token function">addConditionWaiter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 完全释放占有的锁,这里需要是占有锁的线程</span>
<span class="token keyword">int</span> savedState <span class="token operator">=</span> <span class="token function">fullyRelease</span><span class="token punctuation">(</span>node<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> interruptMode <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token comment">// 判断下是否在阻塞队列中,因为有可能被其他节点从等待队列移动到阻塞队列</span>
<span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">isOnSyncQueue</span><span class="token punctuation">(</span>node<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// park等待,等待被唤醒</span>
<span class="token class-name">LockSupport</span><span class="token punctuation">.</span><span class="token function">park</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>interruptMode <span class="token operator">=</span> <span class="token function">checkInterruptWhileWaiting</span><span class="token punctuation">(</span>node<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">)</span>
<span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// 被唤醒后进入阻塞队列,等待获取锁,这里继续用了fullyRelease返回的 state</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">acquireQueued</span><span class="token punctuation">(</span>node<span class="token punctuation">,</span> savedState<span class="token punctuation">)</span> <span class="token operator">&&</span> interruptMode <span class="token operator">!=</span> <span class="token constant">THROW_IE</span><span class="token punctuation">)</span>
interruptMode <span class="token operator">=</span> <span class="token constant">REINTERRUPT</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>node<span class="token punctuation">.</span>nextWaiter <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token comment">// clean up if cancelled</span>
<span class="token function">unlinkCancelledWaiters</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>interruptMode <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">)</span>
<span class="token function">reportInterruptAfterWait</span><span class="token punctuation">(</span>interruptMode<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span aria-hidden=true class=line-numbers-rows><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>添加条件队列节点<pre class="line-numbers language-java" data-language=java><code class=language-java><span class="token comment">/**
* Adds a new waiter to wait queue.
* @return its new wait node
*/</span>
<span class="token keyword">private</span> <span class="token class-name">Node</span> <span class="token function">addConditionWaiter</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">Node</span> t <span class="token operator">=</span> lastWaiter<span class="token punctuation">;</span>
<span class="token comment">// If lastWaiter is cancelled, clean out.</span>
<span class="token comment">// 如果节点已经不是 CONDITION 状态了,表示已经取消了</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>t <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">&&</span> t<span class="token punctuation">.</span>waitStatus <span class="token operator">!=</span> <span class="token class-name">Node</span><span class="token punctuation">.</span><span class="token constant">CONDITION</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// 把等待队列中取消的节点清理出去</span>
<span class="token function">unlinkCancelledWaiters</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
t <span class="token operator">=</span> lastWaiter<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// 把当前线程包装成waitStatus=CONDITION 的节点</span>
<span class="token class-name">Node</span> node <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Node</span><span class="token punctuation">(</span><span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">currentThread</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token class-name">Node</span><span class="token punctuation">.</span><span class="token constant">CONDITION</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 没有 lastWaiter 节点,直接是 firstWaiter</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>t <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span>
firstWaiter <span class="token operator">=</span> node<span class="token punctuation">;</span>
<span class="token keyword">else</span>
<span class="token comment">// 不然就接在 lastWaiter 后面</span>
t<span class="token punctuation">.</span>nextWaiter <span class="token operator">=</span> node<span class="token punctuation">;</span>
<span class="token comment">// 当前节点就会变成新的 lastWaiter</span>
lastWaiter <span class="token operator">=</span> node<span class="token punctuation">;</span>
<span class="token keyword">return</span> node<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span aria-hidden=true class=line-numbers-rows><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>清理取消的节点<pre class="line-numbers language-java" data-language=java><code class=language-java><span class="token comment">/**
* Unlinks cancelled waiter nodes from condition queue.
* Called only while holding lock. This is called when
* cancellation occurred during condition wait, and upon
* insertion of a new waiter when lastWaiter is seen to have
* been cancelled. This method is needed to avoid garbage
* retention in the absence of signals. So even though it may
* require a full traversal, it comes into play only when
* timeouts or cancellations occur in the absence of
* signals. It traverses all nodes rather than stopping at a
* particular target to unlink all pointers to garbage nodes
* without requiring many re-traversals during cancellation
* storms.
*/</span>
<span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">unlinkCancelledWaiters</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">Node</span> t <span class="token operator">=</span> firstWaiter<span class="token punctuation">;</span>
<span class="token class-name">Node</span> trail <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token comment">// 循环遍历单向链表的节点,如果状态不是 CONDITION 就清出去</span>
<span class="token keyword">while</span> <span class="token punctuation">(</span>t <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">Node</span> next <span class="token operator">=</span> t<span class="token punctuation">.</span>nextWaiter<span class="token punctuation">;</span>
<span class="token comment">// 循环链表操作,清掉取消的节点</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>t<span class="token punctuation">.</span>waitStatus <span class="token operator">!=</span> <span class="token class-name">Node</span><span class="token punctuation">.</span><span class="token constant">CONDITION</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
t<span class="token punctuation">.</span>nextWaiter <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>trail <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span>
firstWaiter <span class="token operator">=</span> next<span class="token punctuation">;</span>
<span class="token keyword">else</span>
trail<span class="token punctuation">.</span>nextWaiter <span class="token operator">=</span> next<span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>next <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span>
lastWaiter <span class="token operator">=</span> trail<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">else</span>
trail <span class="token operator">=</span> t<span class="token punctuation">;</span>
t <span class="token operator">=</span> next<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span aria-hidden=true class=line-numbers-rows><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>完全释放锁<pre class="line-numbers language-java" data-language=java><code class=language-java><span class="token comment">/**
* Invokes release with current state value; returns saved state.
* Cancels node and throws exception on failure.
* @param node the condition node for this wait
* @return previous sync state
*/</span>
<span class="token keyword">final</span> <span class="token keyword">int</span> <span class="token function">fullyRelease</span><span class="token punctuation">(</span><span class="token class-name">Node</span> node<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">boolean</span> failed <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token comment">// 获取下当前的 state 值,因为是可重入的,所以这个值要保存下来</span>
<span class="token keyword">int</span> savedState <span class="token operator">=</span> <span class="token function">getState</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 这里还包含比较多操作,不过跟前面分析 AQS 的释放比较类似,不深入了</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">release</span><span class="token punctuation">(</span>savedState<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
failed <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
<span class="token comment">// 返回这个值</span>
<span class="token keyword">return</span> savedState<span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
<span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">IllegalMonitorStateException</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span> <span class="token keyword">finally</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>failed<span class="token punctuation">)</span>
node<span class="token punctuation">.</span>waitStatus <span class="token operator">=</span> <span class="token class-name">Node</span><span class="token punctuation">.</span><span class="token constant">CANCELLED</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span aria-hidden=true class=line-numbers-rows><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>判断是否在阻塞队列中<pre class="line-numbers language-java" data-language=java><code class=language-java><span class="token comment">/**
* Returns true if a node, always one that was initially placed on
* a condition queue, is now waiting to reacquire on sync queue.
* @param node the node
* @return true if is reacquiring
*/</span>
<span class="token keyword">final</span> <span class="token keyword">boolean</span> <span class="token function">isOnSyncQueue</span><span class="token punctuation">(</span><span class="token class-name">Node</span> node<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// 如果waitStatus 是 CONDITION 或者没有 prev 前置节点肯定就不在</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>node<span class="token punctuation">.</span>waitStatus <span class="token operator">==</span> <span class="token class-name">Node</span><span class="token punctuation">.</span><span class="token constant">CONDITION</span> <span class="token operator">||</span> node<span class="token punctuation">.</span>prev <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span>
<span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
<span class="token comment">// 这里就是我前面提到的 next 的作用</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>node<span class="token punctuation">.</span>next <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token comment">// If has successor, it must be on queue</span>
<span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
<span class="token comment">// 从 tail 开始找,是否在阻塞队列中</span>
<span class="token comment">/*
* node.prev can be non-null, but not yet on queue because
* the CAS to place it on queue can fail. So we have to
* traverse from tail to make sure it actually made it. It
* will always be near the tail in calls to this method, and
* unless the CAS failed (which is unlikely), it will be
* there, so we hardly ever traverse much.
*/</span>
<span class="token keyword">return</span> <span class="token function">findNodeFromTail</span><span class="token punctuation">(</span>node<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">/**
* Returns true if node is on sync queue by searching backwards from tail.
* Called only when needed by isOnSyncQueue.
* @return true if present
*/</span>
<span class="token keyword">private</span> <span class="token keyword">boolean</span> <span class="token function">findNodeFromTail</span><span class="token punctuation">(</span><span class="token class-name">Node</span> node<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">Node</span> t <span class="token operator">=</span> tail<span class="token punctuation">;</span>
<span class="token comment">// 从 tail 开始,从后往前找</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token punctuation">;</span><span class="token punctuation">;</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>t <span class="token operator">==</span> node<span class="token punctuation">)</span>
<span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>t <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span>
<span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
t <span class="token operator">=</span> t<span class="token punctuation">.</span>prev<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span aria-hidden=true class=line-numbers-rows><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>await 的逻辑差不多就是这样子,主要的就是把自己包成一个 Node 节点,waitStatus 的状态是 CONDITION,挂在等待队列的最后,然后完全释放锁,park 等待<h2 id=signal><a class=headerlink href=#signal title=signal></a>signal</h2><pre class="line-numbers language-java" data-language=java><code class=language-java><span class="token comment">/**
* Moves the longest-waiting thread, if one exists, from the
* wait queue for this condition to the wait queue for the
* owning lock.
*
* @throws IllegalMonitorStateException if {@link #isHeldExclusively}
* returns {@code false}
*/</span>
<span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">void</span> <span class="token function">signal</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">isHeldExclusively</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">IllegalMonitorStateException</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// firstWaiter 肯定是最早开始等待的</span>
<span class="token class-name">Node</span> first <span class="token operator">=</span> firstWaiter<span class="token punctuation">;</span>
<span class="token comment">// 如果不为空就唤醒</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>first <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span>
<span class="token function">doSignal</span><span class="token punctuation">(</span>first<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">/**
* Removes and transfers nodes until hit non-cancelled one or
* null. Split out from signal in part to encourage compilers
* to inline the case of no waiters.
* @param first (non-null) the first node on condition queue
*/</span>
<span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">doSignal</span><span class="token punctuation">(</span><span class="token class-name">Node</span> first<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">do</span> <span class="token punctuation">{</span>
<span class="token comment">// 因为要去唤醒 first 节点了,firstWaiter 需要再从后面找一个</span>
<span class="token comment">// 并且判断是否为空,如果是空的话就直接可以把 lastWaiter 设置成空了</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span>firstWaiter <span class="token operator">=</span> first<span class="token punctuation">.</span>nextWaiter<span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span>
lastWaiter <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token comment">// first 不需要继续保存后面的 waiter 了,因为 firstWaiter 已经是 first 的后置节点了</span>
first<span class="token punctuation">.</span>nextWaiter <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token comment">// 如果 first 节点转移不成功,并且 firstWaiter 节点不为空,则继续进入循环</span>
<span class="token punctuation">}</span> <span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">transferForSignal</span><span class="token punctuation">(</span>first<span class="token punctuation">)</span> <span class="token operator">&&</span>
<span class="token punctuation">(</span>first <span class="token operator">=</span> firstWaiter<span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">/**
* Transfers a node from a condition queue onto sync queue.
* Returns true if successful.
* @param node the node
* @return true if successfully transferred (else the node was
* cancelled before signal)
*/</span>
<span class="token keyword">final</span> <span class="token keyword">boolean</span> <span class="token function">transferForSignal</span><span class="token punctuation">(</span><span class="token class-name">Node</span> node<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">/*
* If cannot change waitStatus, the node has been cancelled.
*/</span>
<span class="token comment">// 如果状态已经不是 CONDITION 就不会设置成功,返回 false</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">compareAndSetWaitStatus</span><span class="token punctuation">(</span>node<span class="token punctuation">,</span> <span class="token class-name">Node</span><span class="token punctuation">.</span><span class="token constant">CONDITION</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
<span class="token comment">/*
* Splice onto queue and try to set waitStatus of predecessor to
* indicate that thread is (probably) waiting. If cancelled or
* attempt to set waitStatus fails, wake up to resync (in which
* case the waitStatus can be transiently and harmlessly wrong).
*/</span>
<span class="token comment">// 调用跟aqs 第一篇中一样的 enq 方法进入阻塞队列,返回入队后的前一节点</span>
<span class="token class-name">Node</span> p <span class="token operator">=</span> <span class="token function">enq</span><span class="token punctuation">(</span>node<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> ws <span class="token operator">=</span> p<span class="token punctuation">.</span>waitStatus<span class="token punctuation">;</span>
<span class="token comment">// 将前置节点状态设置成SIGNAL,表示后面有节点在等了</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>ws <span class="token operator">></span> <span class="token number">0</span> <span class="token operator">||</span> <span class="token operator">!</span><span class="token function">compareAndSetWaitStatus</span><span class="token punctuation">(</span>p<span class="token punctuation">,</span> ws<span class="token punctuation">,</span> <span class="token class-name">Node</span><span class="token punctuation">.</span><span class="token constant">SIGNAL</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token class-name">LockSupport</span><span class="token punctuation">.</span><span class="token function">unpark</span><span class="token punctuation">(</span>node<span class="token punctuation">.</span>thread<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 返回 true,上一个方法的循环就退出了</span>
<span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span aria-hidden=true class=line-numbers-rows><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>这里其实就是把 condition 等待队列的第一个未取消的节点入队到阻塞队列去争锁<h2 id=附录><a class=headerlink href=#附录 title=附录></a>附录</h2><p><code>synchronized</code> 版的 BoundedBuffer<pre class="line-numbers language-java" data-language=java><code class=language-java><span class="token comment">/*
File: BoundedBuffer.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
11Jun1998 dl Create public version
17Jul1998 dl Simplified by eliminating wait counts
25aug1998 dl added peek
5May1999 dl replace % with conditional (slightly faster)
*/</span>
<span class="token keyword">package</span> <span class="token constant">EDU</span><span class="token punctuation">.</span>oswego<span class="token punctuation">.</span>cs<span class="token punctuation">.</span>dl<span class="token punctuation">.</span>util<span class="token punctuation">.</span>concurrent<span class="token punctuation">;</span>
<span class="token comment">/**
* Efficient array-based bounded buffer class.
* Adapted from CPJ, chapter 8, which describes design.
* &LTp>[&LTa href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. &LT/a>] &LTp>
**/</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">BoundedBuffer</span> <span class="token keyword">implements</span> <span class="token class-name">BoundedChannel</span> <span class="token punctuation">{</span>
<span class="token keyword">protected</span> <span class="token keyword">final</span> <span class="token class-name">Object</span><span class="token punctuation">[</span><span class="token punctuation">]</span> array_<span class="token punctuation">;</span> <span class="token comment">// the elements</span>
<span class="token keyword">protected</span> <span class="token keyword">int</span> takePtr_ <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token comment">// circular indices</span>
<span class="token keyword">protected</span> <span class="token keyword">int</span> putPtr_ <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">protected</span> <span class="token keyword">int</span> usedSlots_ <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token comment">// length</span>
<span class="token keyword">protected</span> <span class="token keyword">int</span> emptySlots_<span class="token punctuation">;</span> <span class="token comment">// capacity - length</span>
<span class="token comment">/**
* Helper monitor to handle puts.
**/</span>
<span class="token keyword">protected</span> <span class="token keyword">final</span> <span class="token class-name">Object</span> putMonitor_ <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Object</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">/**
* Create a BoundedBuffer with the given capacity.
* @exception IllegalArgumentException if capacity less or equal to zero
**/</span>
<span class="token keyword">public</span> <span class="token class-name">BoundedBuffer</span><span class="token punctuation">(</span><span class="token keyword">int</span> capacity<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">IllegalArgumentException</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>capacity <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">IllegalArgumentException</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
array_ <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Object</span><span class="token punctuation">[</span>capacity<span class="token punctuation">]</span><span class="token punctuation">;</span>
emptySlots_ <span class="token operator">=</span> capacity<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">/**
* Create a buffer with the current default capacity
**/</span>
<span class="token keyword">public</span> <span class="token class-name">BoundedBuffer</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">this</span><span class="token punctuation">(</span><span class="token class-name">DefaultChannelCapacity</span><span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">/**
* Return the number of elements in the buffer.
* This is only a snapshot value, that may change
* immediately after returning.
**/</span>
<span class="token keyword">public</span> <span class="token keyword">synchronized</span> <span class="token keyword">int</span> <span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> usedSlots_<span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">int</span> <span class="token function">capacity</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> array_<span class="token punctuation">.</span>length<span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token keyword">protected</span> <span class="token keyword">void</span> <span class="token function">incEmptySlots</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">synchronized</span><span class="token punctuation">(</span>putMonitor_<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token operator">++</span>emptySlots_<span class="token punctuation">;</span>
putMonitor_<span class="token punctuation">.</span><span class="token function">notify</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">protected</span> <span class="token keyword">synchronized</span> <span class="token keyword">void</span> <span class="token function">incUsedSlots</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token operator">++</span>usedSlots_<span class="token punctuation">;</span>
<span class="token function">notify</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">protected</span> <span class="token keyword">final</span> <span class="token keyword">void</span> <span class="token function">insert</span><span class="token punctuation">(</span><span class="token class-name">Object</span> x<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// mechanics of put</span>
<span class="token operator">--</span>emptySlots_<span class="token punctuation">;</span>
array_<span class="token punctuation">[</span>putPtr_<span class="token punctuation">]</span> <span class="token operator">=</span> x<span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">++</span>putPtr_ <span class="token operator">>=</span> array_<span class="token punctuation">.</span>length<span class="token punctuation">)</span> putPtr_ <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">protected</span> <span class="token keyword">final</span> <span class="token class-name">Object</span> <span class="token function">extract</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// mechanics of take</span>
<span class="token operator">--</span>usedSlots_<span class="token punctuation">;</span>
<span class="token class-name">Object</span> old <span class="token operator">=</span> array_<span class="token punctuation">[</span>takePtr_<span class="token punctuation">]</span><span class="token punctuation">;</span>
array_<span class="token punctuation">[</span>takePtr_<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">++</span>takePtr_ <span class="token operator">>=</span> array_<span class="token punctuation">.</span>length<span class="token punctuation">)</span> takePtr_ <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> old<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token class-name">Object</span> <span class="token function">peek</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">synchronized</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>usedSlots_ <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span>
<span class="token keyword">return</span> array_<span class="token punctuation">[</span>takePtr_<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">else</span>
<span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">put</span><span class="token punctuation">(</span><span class="token class-name">Object</span> x<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">InterruptedException</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>x <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">IllegalArgumentException</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">interrupted</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">InterruptedException</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">synchronized</span><span class="token punctuation">(</span>putMonitor_<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">while</span> <span class="token punctuation">(</span>emptySlots_ <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span> putMonitor_<span class="token punctuation">.</span><span class="token function">wait</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">InterruptedException</span> ex<span class="token punctuation">)</span> <span class="token punctuation">{</span>
putMonitor_<span class="token punctuation">.</span><span class="token function">notify</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">throw</span> ex<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token function">insert</span><span class="token punctuation">(</span>x<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">incUsedSlots</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">offer</span><span class="token punctuation">(</span><span class="token class-name">Object</span> x<span class="token punctuation">,</span> <span class="token keyword">long</span> msecs<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">InterruptedException</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>x <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">IllegalArgumentException</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">interrupted</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">InterruptedException</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">synchronized</span><span class="token punctuation">(</span>putMonitor_<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">long</span> start <span class="token operator">=</span> <span class="token punctuation">(</span>msecs <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token operator">?</span> <span class="token number">0</span> <span class="token operator">:</span> <span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">currentTimeMillis</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">long</span> waitTime <span class="token operator">=</span> msecs<span class="token punctuation">;</span>
<span class="token keyword">while</span> <span class="token punctuation">(</span>emptySlots_ <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>waitTime <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span> putMonitor_<span class="token punctuation">.</span><span class="token function">wait</span><span class="token punctuation">(</span>waitTime<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">InterruptedException</span> ex<span class="token punctuation">)</span> <span class="token punctuation">{</span>
putMonitor_<span class="token punctuation">.</span><span class="token function">notify</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">throw</span> ex<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
waitTime <span class="token operator">=</span> msecs <span class="token operator">-</span> <span class="token punctuation">(</span><span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">currentTimeMillis</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> start<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">insert</span><span class="token punctuation">(</span>x<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">incUsedSlots</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token class-name">Object</span> <span class="token function">take</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">InterruptedException</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">interrupted</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">InterruptedException</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Object</span> old <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token keyword">synchronized</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">while</span> <span class="token punctuation">(</span>usedSlots_ <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span> <span class="token function">wait</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">InterruptedException</span> ex<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">notify</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">throw</span> ex<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
old <span class="token operator">=</span> <span class="token function">extract</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">incEmptySlots</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> old<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token class-name">Object</span> <span class="token function">poll</span><span class="token punctuation">(</span><span class="token keyword">long</span> msecs<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">InterruptedException</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">interrupted</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">InterruptedException</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Object</span> old <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token keyword">synchronized</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">long</span> start <span class="token operator">=</span> <span class="token punctuation">(</span>msecs <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token operator">?</span> <span class="token number">0</span> <span class="token operator">:</span> <span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">currentTimeMillis</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">long</span> waitTime <span class="token operator">=</span> msecs<span class="token punctuation">;</span>
<span class="token keyword">while</span> <span class="token punctuation">(</span>usedSlots_ <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>waitTime <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span> <span class="token function">wait</span><span class="token punctuation">(</span>waitTime<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">InterruptedException</span> ex<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">notify</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">throw</span> ex<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
waitTime <span class="token operator">=</span> msecs <span class="token operator">-</span> <span class="token punctuation">(</span><span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">currentTimeMillis</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> start<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
old <span class="token operator">=</span> <span class="token function">extract</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">incEmptySlots</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> old<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span aria-hidden=true class=line-numbers-rows><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div><footer class=post-footer><div class=post-eof></div></footer></article></div><div class=post-block><article class=post-content itemscope itemtype=http://schema.org/Article><link href=https://nicksxs.me/2021/02/14/AQS%E7%AF%87%E4%B8%80/ itemprop=mainEntityOfPage><span hidden itemprop=author itemscope itemtype=http://schema.org/Person><meta content=/uploads/avatar.jpg itemprop=image><meta content=Nicksxs itemprop=name></span><span hidden itemprop=publisher itemscope itemtype=http://schema.org/Organization><meta content="Nicksxs's Blog" itemprop=name><meta content="learn from zero,技术博客,Nicksxs,史学森" itemprop=description></span><span hidden itemprop=post itemscope itemtype=http://schema.org/CreativeWork><meta content="undefined | Nicksxs's Blog" itemprop=name><meta itemprop=description></span><header class=post-header><h2 itemprop="name headline" class=post-title><a class=post-title-link href=/2021/02/14/AQS%E7%AF%87%E4%B8%80/ itemprop=url>AQS篇一</a></h2><div class=post-meta-container><div class=post-meta><span class=post-meta-item><span class=post-meta-item-icon><i class="far fa-calendar"></i> </span><span class=post-meta-item-text>发表于</span> <time itemprop="dateCreated datePublished" title="创建时间:2021-02-14 22:51:54" datetime=2021-02-14T22:51:54+08:00>2021-02-14</time> </span><span class=post-meta-item><span class=post-meta-item-icon><i class="far fa-calendar-check"></i> </span><span class=post-meta-item-text>更新于</span> <time title="修改时间:2021-02-28 20:02:18" datetime=2021-02-28T20:02:18+08:00 itemprop=dateModified>2021-02-28</time> </span><span class=post-meta-item><span class=post-meta-item-icon><i class="far fa-folder"></i> </span><span class=post-meta-item-text>分类于</span> <span itemprop=about itemscope itemtype=http://schema.org/Thing><a href=/categories/Java/ itemprop=url rel=index><span itemprop=name>Java</span></a> </span><span itemprop=about itemscope itemtype=http://schema.org/Thing><a href=/categories/Java/%E5%B9%B6%E5%8F%91/ itemprop=url rel=index><span itemprop=name>并发</span></a> </span></span><span class="post-meta-item leancloud_visitors" data-flag-title=AQS篇一 id=/2021/02/14/AQS%E7%AF%87%E4%B8%80/ title=阅读次数><span class=post-meta-item-icon><i class="far fa-eye"></i> </span><span class=post-meta-item-text>阅读次数:</span> <span class=leancloud-visitors-count></span> </span><span class=post-meta-item><span class=post-meta-item-icon><i class="far fa-comment"></i> </span><span class=post-meta-item-text>Disqus:</span> <a href=/2021/02/14/AQS%E7%AF%87%E4%B8%80/#disqus_thread itemprop=discussionUrl title=disqus><span class="post-comments-count disqus-comment-count" data-disqus-identifier=2021/02/14/AQS篇一/ itemprop=commentCount></span></a></span></div></div></header><div class=post-body itemprop=articleBody><p>很多东西都是时看时新,而且时间长了也会忘,所以再来复习下,也会有一些新的角度看法这次来聊下AQS的内容,主要是这几个点,<h2 id=第一个线程><a class=headerlink href=#第一个线程 title=第一个线程></a>第一个线程</h2><p>第一个线程抢到锁了,此时state跟阻塞队列是怎么样的,其实这里是之前没理解对的地方<pre class="line-numbers language-java" data-language=java><code class=language-java><span class="token comment">/**
* Fair version of tryAcquire. Don't grant access unless
* recursive call or no waiters or is first.
*/</span>
<span class="token keyword">protected</span> <span class="token keyword">final</span> <span class="token keyword">boolean</span> <span class="token function">tryAcquire</span><span class="token punctuation">(</span><span class="token keyword">int</span> acquires<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">final</span> <span class="token class-name">Thread</span> current <span class="token operator">=</span> <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">currentThread</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> c <span class="token operator">=</span> <span class="token function">getState</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 这里如果state还是0说明锁还空着</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>c <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// 因为是公平锁版本的,先去看下是否阻塞队列里有排着队的</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">hasQueuedPredecessors</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&&</span>
<span class="token function">compareAndSetState</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> acquires<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// 没有排队的,并且state使用cas设置成功的就标记当前占有锁的线程是我</span>
<span class="token function">setExclusiveOwnerThread</span><span class="token punctuation">(</span>current<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 然后其实就返回了,包括阻塞队列的head和tail节点和waitStatus都没有设置</span>
<span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>current <span class="token operator">==</span> <span class="token function">getExclusiveOwnerThread</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">int</span> nextc <span class="token operator">=</span> c <span class="token operator">+</span> acquires<span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>nextc <span class="token operator"><</span> <span class="token number">0</span><span class="token punctuation">)</span>
<span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">"Maximum lock count exceeded"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">setState</span><span class="token punctuation">(</span>nextc<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// 这里就是第二个线程会返回false</span>
<span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span aria-hidden=true class=line-numbers-rows><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h2 id=第二个线程><a class=headerlink href=#第二个线程 title=第二个线程></a>第二个线程</h2><p>当第二个线程进来的时候应该是怎么样,结合代码来看<pre class="line-numbers language-java" data-language=java><code class=language-java><span class="token comment">/**
* Acquires in exclusive mode, ignoring interrupts. Implemented
* by invoking at least once {@link #tryAcquire},
* returning on success. Otherwise the thread is queued, possibly
* repeatedly blocking and unblocking, invoking {@link
* #tryAcquire} until success. This method can be used
* to implement method {@link Lock#lock}.
*
* @param arg the acquire argument. This value is conveyed to
* {@link #tryAcquire} but is otherwise uninterpreted and
* can represent anything you like.
*/</span>
<span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">void</span> <span class="token function">acquire</span><span class="token punctuation">(</span><span class="token keyword">int</span> arg<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// 前面第一种情况是tryAcquire直接成功了,这个if判断第一个条件就是false,就不往下执行了</span>
<span class="token comment">// 如果是第二个线程,第一个条件获取锁不成功,条件判断!tryAcquire(arg) == true,就会走</span>
<span class="token comment">// acquireQueued(addWaiter(Node.EXCLUSIVE), arg)</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">tryAcquire</span><span class="token punctuation">(</span>arg<span class="token punctuation">)</span> <span class="token operator">&&</span>
<span class="token function">acquireQueued</span><span class="token punctuation">(</span><span class="token function">addWaiter</span><span class="token punctuation">(</span><span class="token class-name">Node</span><span class="token punctuation">.</span><span class="token constant">EXCLUSIVE</span><span class="token punctuation">)</span><span class="token punctuation">,</span> arg<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token function">selfInterrupt</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span aria-hidden=true class=line-numbers-rows><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>然后来看下addWaiter的逻辑<pre class="line-numbers language-java" data-language=java><code class=language-java><span class="token comment">/**
* Creates and enqueues node for current thread and given mode.
*
* @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared
* @return the new node
*/</span>
<span class="token keyword">private</span> <span class="token class-name">Node</span> <span class="token function">addWaiter</span><span class="token punctuation">(</span><span class="token class-name">Node</span> mode<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// 这里是包装成一个node</span>
<span class="token class-name">Node</span> node <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Node</span><span class="token punctuation">(</span><span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">currentThread</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> mode<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Try the fast path of enq; backup to full enq on failure</span>
<span class="token comment">// 最快的方式就是把当前线程的节点放在阻塞队列的最后</span>
<span class="token class-name">Node</span> pred <span class="token operator">=</span> tail<span class="token punctuation">;</span>
<span class="token comment">// 只有当tail,也就是pred不为空的时候可以直接接上</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>pred <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
node<span class="token punctuation">.</span>prev <span class="token operator">=</span> pred<span class="token punctuation">;</span>
<span class="token comment">// 如果这里cas成功了,就直接接上返回了</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">compareAndSetTail</span><span class="token punctuation">(</span>pred<span class="token punctuation">,</span> node<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
pred<span class="token punctuation">.</span>next <span class="token operator">=</span> node<span class="token punctuation">;</span>
<span class="token keyword">return</span> node<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token comment">// 不然就会继续走到这里</span>
<span class="token function">enq</span><span class="token punctuation">(</span>node<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> node<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span aria-hidden=true class=line-numbers-rows><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>然后就是enq的逻辑了<pre class="line-numbers language-java" data-language=java><code class=language-java><span class="token comment">/**
* Inserts node into queue, initializing if necessary. See picture above.
* @param node the node to insert
* @return node's predecessor
*/</span>
<span class="token keyword">private</span> <span class="token class-name">Node</span> <span class="token function">enq</span><span class="token punctuation">(</span><span class="token keyword">final</span> <span class="token class-name">Node</span> node<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token punctuation">;</span><span class="token punctuation">;</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// 如果状态没变化的话,tail这时还是null的</span>
<span class="token class-name">Node</span> t <span class="token operator">=</span> tail<span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>t <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// Must initialize</span>
<span class="token comment">// 这里就会初始化头结点,就是个空节点</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">compareAndSetHead</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Node</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token comment">// tail也赋值成head</span>
tail <span class="token operator">=</span> head<span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
<span class="token comment">// 这里就设置tail了</span>
node<span class="token punctuation">.</span>prev <span class="token operator">=</span> t<span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">compareAndSetTail</span><span class="token punctuation">(</span>t<span class="token punctuation">,</span> node<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
t<span class="token punctuation">.</span>next <span class="token operator">=</span> node<span class="token punctuation">;</span>
<span class="token keyword">return</span> t<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span aria-hidden=true class=line-numbers-rows><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>所以从这里可以看出来,其实head头结点不是个真实的带有线程的节点,并且不是在第一个线程进来的时候设置的<h2 id=解锁><a class=headerlink href=#解锁 title=解锁></a>解锁</h2><p>通过代码来看下<pre class="line-numbers language-java" data-language=java><code class=language-java><span class="token comment">/**
* Attempts to release this lock.
*
* &LTp>If the current thread is the holder of this lock then the hold
* count is decremented. If the hold count is now zero then the lock
* is released. If the current thread is not the holder of this
* lock then {@link IllegalMonitorStateException} is thrown.
*
* @throws IllegalMonitorStateException if the current thread does not
* hold this lock
*/</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">unlock</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// 释放锁</span>
sync<span class="token punctuation">.</span><span class="token function">release</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">/**
* Releases in exclusive mode. Implemented by unblocking one or
* more threads if {@link #tryRelease} returns true.
* This method can be used to implement method {@link Lock#unlock}.
*
* @param arg the release argument. This value is conveyed to
* {@link #tryRelease} but is otherwise uninterpreted and
* can represent anything you like.
* @return the value returned from {@link #tryRelease}
*/</span>
<span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">boolean</span> <span class="token function">release</span><span class="token punctuation">(</span><span class="token keyword">int</span> arg<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// 尝试去释放</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">tryRelease</span><span class="token punctuation">(</span>arg<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">Node</span> h <span class="token operator">=</span> head<span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>h <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">&&</span> h<span class="token punctuation">.</span>waitStatus <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">)</span>
<span class="token function">unparkSuccessor</span><span class="token punctuation">(</span>h<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">protected</span> <span class="token keyword">final</span> <span class="token keyword">boolean</span> <span class="token function">tryRelease</span><span class="token punctuation">(</span><span class="token keyword">int</span> releases<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">int</span> c <span class="token operator">=</span> <span class="token function">getState</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> releases<span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">currentThread</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token function">getExclusiveOwnerThread</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">IllegalMonitorStateException</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">boolean</span> free <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
<span class="token comment">// 判断是否完全释放锁,因为可重入</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>c <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
free <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
<span class="token function">setExclusiveOwnerThread</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">setState</span><span class="token punctuation">(</span>c<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> free<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// 这段代码和上面的一致,只是为了顺序性,又拷下来看下</span>
<span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">boolean</span> <span class="token function">release</span><span class="token punctuation">(</span><span class="token keyword">int</span> arg<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// 尝试去释放,如果是完全释放,返回的就是true,否则是false</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">tryRelease</span><span class="token punctuation">(</span>arg<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">Node</span> h <span class="token operator">=</span> head<span class="token punctuation">;</span>
<span class="token comment">// 这里判断头结点是否为空以及waitStatus的状态,前面说了head节点其实是</span>
<span class="token comment">// 在第二个线程进来的时候初始化的,如果是空的话说明没后续节点,并且waitStatus</span>
<span class="token comment">// 也表示了后续的等待状态</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>h <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">&&</span> h<span class="token punctuation">.</span>waitStatus <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">)</span>
<span class="token function">unparkSuccessor</span><span class="token punctuation">(</span>h<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">/**
* Wakes up node's successor, if one exists.
*
* @param node the node
*/</span>
<span class="token comment">// 唤醒后继节点</span>
<span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">unparkSuccessor</span><span class="token punctuation">(</span><span class="token class-name">Node</span> node<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">/*
* If status is negative (i.e., possibly needing signal) try
* to clear in anticipation of signalling. It is OK if this
* fails or if status is changed by waiting thread.
*/</span>
<span class="token keyword">int</span> ws <span class="token operator">=</span> node<span class="token punctuation">.</span>waitStatus<span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>ws <span class="token operator"><</span> <span class="token number">0</span><span class="token punctuation">)</span>
<span class="token function">compareAndSetWaitStatus</span><span class="token punctuation">(</span>node<span class="token punctuation">,</span> ws<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">/*
* Thread to unpark is held in successor, which is normally
* just the next node. But if cancelled or apparently null,
* traverse backwards from tail to find the actual
* non-cancelled successor.
*/</span>
<span class="token class-name">Node</span> s <span class="token operator">=</span> node<span class="token punctuation">.</span>next<span class="token punctuation">;</span>
<span class="token comment">// 如果后继节点是空或者当前节点取消等待了</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>s <span class="token operator">==</span> <span class="token keyword">null</span> <span class="token operator">||</span> s<span class="token punctuation">.</span>waitStatus <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
s <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token comment">// 从后往前找,找到非取消的节点,注意这里不是找到就退出,而是一直找到头</span>
<span class="token comment">// 所以不必担心中间有取消的</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">Node</span> t <span class="token operator">=</span> tail<span class="token punctuation">;</span> t <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">&&</span> t <span class="token operator">!=</span> node<span class="token punctuation">;</span> t <span class="token operator">=</span> t<span class="token punctuation">.</span>prev<span class="token punctuation">)</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>t<span class="token punctuation">.</span>waitStatus <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">)</span>
s <span class="token operator">=</span> t<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>s <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span>
<span class="token comment">// 将其唤醒</span>
<span class="token class-name">LockSupport</span><span class="token punctuation">.</span><span class="token function">unpark</span><span class="token punctuation">(</span>s<span class="token punctuation">.</span>thread<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span aria-hidden=true class=line-numbers-rows><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div><footer class=post-footer><div class=post-eof></div></footer></article></div><nav class=pagination><a class="extend prev" aria-label=上一页 href=/page/28/ rel=prev title=上一页><i class="fa fa-angle-left"></i></a><a class=page-number href=/>1</a><span class=space></span><a class=page-number href=/page/28/>28</a><span class="page-number current">29</span><a class=page-number href=/page/30/>30</a><span class=space></span><a class=page-number href=/page/47/>47</a><a class="extend next" aria-label=下一页 href=/page/30/ rel=next title=下一页><i class="fa fa-angle-right"></i></a></nav></div></main><footer class=footer><div class=footer-inner><div class=beian><a href=https://beian.miit.gov.cn/ rel=noopener target=_blank>浙ICP备16002580号-2 </a><img alt src=/uploads/beian.png><a href=http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=33010602011094 rel=noopener target=_blank>浙公网安备 33010602011094号</a></div><div class=copyright>© <span itemprop=copyrightYear>2023</span><span class=with-love><i class="fa fa-heart"></i> </span><span class=author itemprop=copyrightHolder>Nicksxs</span></div><div class=busuanzi-count><span class=post-meta-item id=busuanzi_container_site_uv><span class=post-meta-item-icon><i class="fa fa-user"></i> </span><span class=site-uv title=总访客量><span id=busuanzi_value_site_uv></span> </span></span><span class=post-meta-item id=busuanzi_container_site_pv><span class=post-meta-item-icon><i class="fa fa-eye"></i> </span><span class=site-pv title=总访问量><span id=busuanzi_value_site_pv></span></span></span></div></div></footer><div aria-label=返回顶部 class=back-to-top role=button><i class="fa fa-arrow-up fa-lg"></i><span>0%</span></div><a aria-label="Follow me on GitHub" title="Follow me on GitHub" class=github-corner href=https://github.com/nicksxs rel=noopener target=_blank><svg viewbox="0 0 250 250" aria-hidden=true height=80 width=80><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" style="transform-origin:130px 106px" class=octo-arm fill=currentColor></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" class=octo-body fill=currentColor></path></svg></a><noscript><div class=noscript-warning>Theme NexT works best with JavaScript enabled</div></noscript><script crossorigin=anonymous integrity=sha256-XL2inqUJaslATFnHdJOi9GfQ60on8Wx1C2H8DYiN1xY= src=https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js></script><script crossorigin=anonymous integrity=sha256-pvPw+upLPUjgMXY0G+8O0xUf+/Im1MZjXxxgOcBQBXU= src=https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.3/jquery.min.js></script><script crossorigin=anonymous integrity=sha256-yt2kYMy0w8AbtF89WXb2P1rfjcP/HTHLT7097U8Y5b8= src=https://cdnjs.cloudflare.com/ajax/libs/fancybox/3.5.7/jquery.fancybox.min.js></script><script crossorigin=anonymous integrity=sha256-mOFREFhqmHeQbXpK2lp4nA3qooVgACfh88fpJftLBbc= src=https://cdnjs.cloudflare.com/ajax/libs/lozad.js/1.16.0/lozad.min.js></script><script src=/js/comments.js></script><script src=/js/utils.js></script><script src=/js/motion.js></script><script src=/js/next-boot.js></script><script crossorigin=anonymous integrity=sha256-dyJcbGuYfdzNfifkHxYVd/rzeR6SLLcDFYEidcybldM= src=https://cdnjs.cloudflare.com/ajax/libs/algoliasearch/4.14.3/algoliasearch-lite.umd.js></script><script crossorigin=anonymous integrity=sha256-Nu8yqoXoRZEVYyZf4/eY1V4FsenbiCw85RY3gWjN3zQ= src=https://cdnjs.cloudflare.com/ajax/libs/instantsearch.js/4.49.2/instantsearch.production.min.js></script><script src=/js/third-party/search/algolia-search.js></script><script src=/js/third-party/fancybox.js></script><script async src=https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js></script><script class=next-config data-name=leancloud_visitors type=application/json>{"enable":true,"app_id":"ysza182Vghlqjdt7QiwGLLJy-gzGzoHsz","app_key":"s9GDqbn7gnGGkusf66YRVccw","server_url":"https://leancloud.cn","security":true}</script><script src=/js/third-party/statistics/lean-analytics.js></script><script crossorigin=anonymous integrity=sha256-yvJQOINiH9fWemHn0vCA5lsHWJaHs6/ZmO+1Ft04SvM= src=https://cdnjs.cloudflare.com/ajax/libs/quicklink/2.3.0/quicklink.umd.js></script><script class=next-config data-name=quicklink type=application/json>{"enable":false,"home":false,"archive":false,"delay":true,"timeout":3000,"priority":true,"url":"https://nicksxs.me/page/29/"}</script><script src=/js/third-party/quicklink.js></script><script class=next-config data-name=disqus type=application/json>{"enable":true,"shortname":"nicksxs","count":true,"i18n":{"disqus":"disqus"}}</script><script src=/js/third-party/comments/disqus.js></script>