<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0"  xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title></title>
    <description></description>
    <link>https://www.iteye.com/blog/user/java8988</link>
    <language>zh-CN</language>
    <copyright>Copyright 2003-2026, ITeye.com</copyright>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>ITeye - 软件开发交流社区</generator>
    <atom:link href="https://www.iteye.com/blog/user/java8988/rss" rel="self" type="application/rss+xml" />
              <item>
            <title>git问题--git 切换分支时，出现HEAD detached解决方案</title>
            <description>
              <![CDATA[
              <div class="iteye-blog-content-contain" style="font-size: 14px;">
<p>原文链接：<a href="https://www.jianshu.com/p/63534c3baec3" title="原文链接" target="_blank">https://www.jianshu.com/p/63534c3baec3</a> 转载请注明出处</p>
<p> </p>
<div class="image-package">
<div class="image-container" style="background-color: transparent; margin: 0px auto; max-width: 700px;">
<div class="image-view" style="width: 700px; height: 175.625px; overflow: hidden;"><img alt="" src="https://upload-images.jianshu.io/upload_images/11336294-00929a81891dbe2b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/853/format/webp"></div>
</div>
<div class="image-caption" style="min-width: 20%; max-width: 80%; display: inline-block; padding: 10px; margin: 0px auto; border-bottom: 1px solid #d9d9d9; font-size: 14px; color: #969696; line-height: 1.7;">1540361271922.png</div>
</div>
<p>从master直接切换到另一分支名(drpV2.0.24)的时候，出现游离状态，没有改动代码，只是想让HEAD从游离状态中恢复到正常分支上，但git checkout drpV2.0.24 并没有用...还是在游离状态...</p>
<h3>解决方法</h3>
<ol>
<li style="line-height: 30px;">git branch -v 查看当前领先多少</li>
</ol>
<div class="image-package">
<div class="image-container" style="background-color: transparent; margin: 0px auto; max-width: 700px;">
<div class="image-container-fill"> </div>
<div class="image-view" style="width: 700px; height: 91.7604px; overflow: hidden;"><img alt="" src="https://upload-images.jianshu.io/upload_images/11336294-0832257d49383d42.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/885/format/webp"></div>
</div>
<div class="image-caption" style="min-width: 20%; max-width: 80%; display: inline-block; padding: 10px; margin: 0px auto; border-bottom: 1px solid #d9d9d9; font-size: 14px; color: #969696; line-height: 1.7;">1540361405219.png</div>
</div>
<pre class="hljs css"><code class="css" style="font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; color: inherit; background-color: transparent; border-radius: 0px; padding: 0px; border: none; vertical-align: middle;"><span class="hljs-selector-tag" style="color: #e06c75;">a9031fb</span> 指向的是`<span class="hljs-selector-tag" style="color: #e06c75;">drpV2</span><span class="hljs-selector-class" style="color: #d19a66;">.0</span><span class="hljs-selector-class" style="color: #d19a66;">.24</span>`的最后一次提交
</code></pre>
<ol>
<li style="line-height: 30px;">新建一个 temp 分支，把当前提交的代码放到整个分支</li>
</ol>
<div class="image-package">
<div class="image-container" style="background-color: transparent; margin: 0px auto; max-width: 700px;">
<div class="image-container-fill" style="padding-bottom: 63px;"> </div>
<div class="image-view" style="width: 700px; height: 63px; overflow: hidden;"><img alt="" src="https://upload-images.jianshu.io/upload_images/11336294-a551beb3d820621e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/856/format/webp"></div>
</div>
<div class="image-caption" style="min-width: 20%; max-width: 80%; display: inline-block; padding: 10px; margin: 0px auto; border-bottom: 1px solid #d9d9d9; font-size: 14px; color: #969696; line-height: 1.7;">1540361524207.png</div>
</div>
<div class="image-package">
<div class="image-container" style="background-color: transparent; margin: 0px auto; max-width: 700px;">
<div class="image-container-fill"> </div>
<div class="image-view" style="width: 700px; height: 161.344px; overflow: hidden;"><img alt="" src="https://upload-images.jianshu.io/upload_images/11336294-3df3faf9eeda6aa0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/833/format/webp"></div>
</div>
<div class="image-caption" style="min-width: 20%; max-width: 80%; display: inline-block; padding: 10px; margin: 0px auto; border-bottom: 1px solid #d9d9d9; font-size: 14px; color: #969696; line-height: 1.7;">1540361605823.png</div>
</div>
<ol>
<li style="line-height: 30px;">
<code style="font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; color: #c7254e; background-color: #f6f6f6; border-radius: 4px; padding: 2px 4px; border: none; white-space: pre-wrap; vertical-align: middle;">checkout</code> 要回到的那个分支，这里是 <code style="font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; color: #c7254e; background-color: #f6f6f6; border-radius: 4px; padding: 2px 4px; border: none; white-space: pre-wrap; vertical-align: middle;">drpV2.0.24</code>
</li>
</ol>
<div class="image-package">
<div class="image-container" style="background-color: transparent; margin: 0px auto; max-width: 700px;">
<div class="image-container-fill"> </div>
<div class="image-view" style="width: 700px; height: 198.583px; overflow: hidden;"><img alt="" src="https://upload-images.jianshu.io/upload_images/11336294-c9ad4d00e9901297.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1000/format/webp"></div>
</div>
<div class="image-caption" style="min-width: 20%; max-width: 80%; display: inline-block; padding: 10px; margin: 0px auto; border-bottom: 1px solid #d9d9d9; font-size: 14px; color: #969696; line-height: 1.7;">1540361658981.png</div>
</div>
<p>发现不再是游离状态</p>
</div>
              
              <br/><br/>
              <span style="color:red;">
                <a href="https://www.iteye.com/blog/java8988-2433260#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
              </span>
              <br/><br/><br/>
<span style="color:#E28822;">ITeye推荐</span>
<br/>
<ul><li><a href='/clicks/433' target='_blank'><span style="color:red;font-weight:bold;">—软件人才免语言低担保 赴美带薪读研！— </span></a></li></ul>
<br/><br/><br/>
              ]]>
            </description>
            <pubDate>Mon, 05 Nov 2018 16:14:16 +0800</pubDate>
            <link>https://www.iteye.com/blog/user/java8988/blog/2433260</link>
            <guid isPermaLink="false">https://www.iteye.com/blog/user/java8988/blog/2433260</guid>
          </item>
                  <item>
            <title>idea设置方法注释(亲测有效)</title>
            <description>
              <![CDATA[
              <div class="iteye-blog-content-contain" style="font-size: 14px;">
<p><a href="https://www.jianshu.com/p/2b17c3879879" style="" target="_blank">原文地址：https://www.jianshu.com/p/2b17c3879879</a></p>
<p> </p>
<p>idea方法注释，系统默认的只能获取到参数，无法获取返回值，如下：</p>
<pre class="hljs java"><code class="java" style="font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 12px; color: inherit; background-color: transparent; border-radius: 0px; padding: 0px; border: none; vertical-align: middle;"><span class="hljs-comment" style="color: #5c6370; font-style: italic;">/**
     * 
     * <span class="hljs-doctag" style="color: #c678dd;">@param</span> id
     * <span class="hljs-doctag" style="color: #c678dd;">@param</span> type
     * <span class="hljs-doctag" style="color: #c678dd;">@return</span>
     */</span>
    <span class="hljs-function"><span class="hljs-keyword" style="color: #c678dd;">public</span> <span class="hljs-keyword" style="color: #c678dd;">static</span> String <span class="hljs-title" style="color: #61aeee;">getName</span><span class="hljs-params">(Long id, <span class="hljs-keyword" style="color: #c678dd;">int</span> type)</span> </span>{
        <span class="hljs-keyword" style="color: #c678dd;">return</span> <span class="hljs-keyword" style="color: #c678dd;">null</span>;
    }
</code></pre>
<p>使用Eclipse时我们生成注释的习惯是/**+Enter，这里我们也按照这种习惯来设置IDEA的方法注释</p>
<h2>1. File--&gt;Settings--&gt;Editor--&gt;Live Templates</h2>
<div class="image-package">
<div class="image-container" style="background-color: transparent; margin: 0px auto; max-width: 700px;">
<div class="image-container-fill"> </div>
<div class="image-view" style="width: 700px; height: 354px; overflow: hidden;"><img alt="" src="https://upload-images.jianshu.io/upload_images/11336294-571aab7c677f8f34.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1000/format/webp"></div>
</div>
<div class="image-caption" style="min-width: 20%; max-width: 80%; display: inline-block; padding: 10px; margin: 0px auto; border-bottom: 1px solid #d9d9d9; font-size: 14px; color: #969696; line-height: 1.7;">1539077097651.png</div>
</div>
<h3>1.1 新建Template Group: 命名为 MethodBingtai</h3>
<div class="image-package">
<div class="image-container" style="background-color: transparent; margin: 0px auto; max-width: 700px;">
<div class="image-container-fill"> </div>
<div class="image-view" style="width: 700px; height: 313px; overflow: hidden;"><img alt="" src="https://upload-images.jianshu.io/upload_images/11336294-c0c118c7b8463b1a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1000/format/webp"></div>
</div>
<div class="image-caption" style="min-width: 20%; max-width: 80%; display: inline-block; padding: 10px; margin: 0px auto; border-bottom: 1px solid #d9d9d9; font-size: 14px; color: #969696; line-height: 1.7;">1539077305313.png</div>
</div>
<h3>1.2 在MethodBingtai下新建Live Template，命名为*</h3>
<div class="image-package">
<div class="image-container" style="background-color: transparent; margin: 0px auto; max-width: 700px;">
<div class="image-container-fill"> </div>
<div class="image-view" style="width: 700px; height: 362px; overflow: hidden;"><img alt="" src="https://upload-images.jianshu.io/upload_images/11336294-972d14b6d9d855e7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1000/format/webp"></div>
</div>
<div class="image-caption" style="min-width: 20%; max-width: 80%; display: inline-block; padding: 10px; margin: 0px auto; border-bottom: 1px solid #d9d9d9; font-size: 14px; color: #969696; line-height: 1.7;">1539077602137.png</div>
</div>
<p> </p>
<div class="image-package">
<div class="image-container" style="background-color: transparent; margin: 0px auto; max-width: 700px;">
<div class="image-container-fill"> </div>
<div class="image-view" style="width: 700px; height: 354px; overflow: hidden;"><img alt="" src="https://upload-images.jianshu.io/upload_images/11336294-fc20d59abc1abb56.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1000/format/webp"></div>
</div>
<div class="image-caption" style="min-width: 20%; max-width: 80%; display: inline-block; padding: 10px; margin: 0px auto; border-bottom: 1px solid #d9d9d9; font-size: 14px; color: #969696; line-height: 1.7;">LiveTemplate.png</div>
</div>
<blockquote>
<p style="line-height: 1.7;">因为IDEA生成注释的默认方式是：/* +模板名+快捷键（比如若设置模板名为add快捷键用Tab，则生成方式为/*add+Tab），如果不采用这样的生成方式IDEA中没有内容的方法将不可用，例如获取方法参数的methodParameters(）、获取方法返回值的methodReturnType(）</p>
</blockquote>
<h3>1.3 设置注释的快捷键</h3>
<div class="image-package">
<div class="image-container" style="background-color: transparent; margin: 0px auto; max-width: 700px;">
<div class="image-container-fill"> </div>
<div class="image-view" style="width: 700px; height: 359px; overflow: hidden;"><img alt="" src="https://upload-images.jianshu.io/upload_images/11336294-d28384a45e91c586.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1000/format/webp"></div>
</div>
<div class="image-caption" style="min-width: 20%; max-width: 80%; display: inline-block; padding: 10px; margin: 0px auto; border-bottom: 1px solid #d9d9d9; font-size: 14px; color: #969696; line-height: 1.7;">TIM截图20181009193521.png</div>
</div>
<h3>1.4 设置模板</h3>
<p>模板内容如下：</p>
<pre class="hljs java"><code class="java" style="font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 12px; color: inherit; background-color: transparent; border-radius: 0px; padding: 0px; border: none; vertical-align: middle;">*
 * 功能描述: &lt;br&gt;
 * 〈$END$〉
 * <span class="hljs-meta" style="color: #61aeee;">@Param</span>: $param$
 * <span class="hljs-meta" style="color: #61aeee;">@Return</span>: $<span class="hljs-keyword" style="color: #c678dd;">return</span>$
 * <span class="hljs-meta" style="color: #61aeee;">@Author</span>: $user$
 * <span class="hljs-meta" style="color: #61aeee;">@Date</span>: $DATE$ $TIME$
 */
</code></pre>
<p><span style="font-weight: bold;">注意</span> 第一行，只有一个* 而不是/*</p>
<p>在设置参数名时必须用<code style="font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 12px; color: #c7254e; background-color: #f6f6f6; border-radius: 4px; padding: 2px 4px; border: none; white-space: pre-wrap; vertical-align: middle;">$参数名$</code>的方式，否则<span style="font-weight: bold;">1.5</span>中读取不到你设置的参数名</p>
<h3>1.5 设置参数的获取方式</h3>
<p>选择右侧的<code style="font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 12px; color: #c7254e; background-color: #f6f6f6; border-radius: 4px; padding: 2px 4px; border: none; white-space: pre-wrap; vertical-align: middle;">Edit variables</code>按钮</p>
<div class="image-package">
<div class="image-container" style="background-color: transparent; margin: 0px auto; max-width: 700px;">
<div class="image-container-fill"> </div>
<div class="image-view" style="width: 700px; height: 406px; overflow: hidden;"><img alt="" src="https://upload-images.jianshu.io/upload_images/11336294-12f1660ff6ed2bf9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1000/format/webp"></div>
</div>
<div class="image-caption" style="min-width: 20%; max-width: 80%; display: inline-block; padding: 10px; margin: 0px auto; border-bottom: 1px solid #d9d9d9; font-size: 14px; color: #969696; line-height: 1.7;">1539078565190.png</div>
</div>
<p> </p>
<p>选择每个参数对应的获取方法（在下拉选择框中选择即可），网上有很多教程说获取param时使用脚本的方式，我试过使用脚本的方式不仅麻烦而且只能在方法内部使用注释时才能获取到参数</p>
<p> </p>
<div class="image-package">
<div class="image-container" style="background-color: transparent; margin: 0px auto; max-width: 700px;">
<div class="image-container-fill"> </div>
<div class="image-view" style="width: 700px; height: 360px; overflow: hidden;"><img alt="" src="https://upload-images.jianshu.io/upload_images/11336294-766dd2b8c1adc1be.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1000/format/webp"></div>
</div>
<div class="image-caption" style="min-width: 20%; max-width: 80%; display: inline-block; padding: 10px; margin: 0px auto; border-bottom: 1px solid #d9d9d9; font-size: 14px; color: #969696; line-height: 1.7;">1539078839738.png</div>
</div>
<p>选择应用场景：勾选Java</p>
<p> </p>
<div class="image-package">
<div class="image-container" style="background-color: transparent; margin: 0px auto; max-width: 700px;">
<div class="image-container-fill"> </div>
<div class="image-view" style="width: 700px; height: 360px; overflow: hidden;"><img alt="" src="https://upload-images.jianshu.io/upload_images/11336294-8e5bb44d1dcabec1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1000/format/webp"></div>
</div>
<div class="image-caption" style="min-width: 20%; max-width: 80%; display: inline-block; padding: 10px; margin: 0px auto; border-bottom: 1px solid #d9d9d9; font-size: 14px; color: #969696; line-height: 1.7;">1539078870502.png</div>
</div>
<p><span style="font-weight: bold;">注意</span> 点击模板页面最下方的警告，来设置将模板应用于那些场景，一般选择Java即可（如果曾经修改过，则显示为<code style="font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 12px; color: #c7254e; background-color: #f6f6f6; border-radius: 4px; padding: 2px 4px; border: none; white-space: pre-wrap; vertical-align: middle;">Change</code>而不是<code style="font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 12px; color: #c7254e; background-color: #f6f6f6; border-radius: 4px; padding: 2px 4px; border: none; white-space: pre-wrap; vertical-align: middle;">Define</code>）</p>
<p>再次选择右侧的<code style="font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 12px; color: #c7254e; background-color: #f6f6f6; border-radius: 4px; padding: 2px 4px; border: none; white-space: pre-wrap; vertical-align: middle;">Edit variables</code>按钮，下拉框就有选项了；如下图，选中对应的<code style="font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 12px; color: #c7254e; background-color: #f6f6f6; border-radius: 4px; padding: 2px 4px; border: none; white-space: pre-wrap; vertical-align: middle;">Expression</code>，点击<code style="font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 12px; color: #c7254e; background-color: #f6f6f6; border-radius: 4px; padding: 2px 4px; border: none; white-space: pre-wrap; vertical-align: middle;">OK</code></p>
<div class="image-package">
<div class="image-container" style="background-color: transparent; margin: 0px auto; max-width: 700px;">
<div class="image-container-fill"> </div>
<div class="image-view" style="width: 700px; height: 283.146px; overflow: hidden;"><img alt="" src="https://upload-images.jianshu.io/upload_images/11336294-c7dbc4779f07227f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1000/format/webp"></div>
</div>
<div class="image-caption" style="min-width: 20%; max-width: 80%; display: inline-block; padding: 10px; margin: 0px auto; border-bottom: 1px solid #d9d9d9; font-size: 14px; color: #969696; line-height: 1.7;">1539079048193.png</div>
</div>
<p> </p>
<h2>2. 效果</h2>
<p>创建方法，在方法上一行，输入 /** ，然后 回车</p>
<p> </p>
<div class="image-package">
<div class="image-container" style="background-color: transparent; margin: 0px auto; max-width: 700px;">
<div class="image-container-fill"> </div>
<div class="image-view" style="width: 700px; height: 475.5px; overflow: hidden;"><img alt="" src="https://upload-images.jianshu.io/upload_images/11336294-648895c7d379fd07.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/767/format/webp"></div>
</div>
<div class="image-caption" style="min-width: 20%; max-width: 80%; display: inline-block; padding: 10px; margin: 0px auto; border-bottom: 1px solid #d9d9d9; font-size: 14px; color: #969696; line-height: 1.7;">1539084053764.png</div>
</div>
<p><span style="font-weight: bold;">参考:</span> <a href="https://blog.csdn.net/xiaoliulang0324/article/details/79030752" style="background-color: transparent; color: #3194d0; cursor: pointer;" target="_blank">IDEA类和方法注释模板设置</a></p>
</div>
              
              <br/><br/>
              <span style="color:red;">
                <a href="https://www.iteye.com/blog/java8988-2431885#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
              </span>
              <br/><br/><br/>
<span style="color:#E28822;">ITeye推荐</span>
<br/>
<ul><li><a href='/clicks/433' target='_blank'><span style="color:red;font-weight:bold;">—软件人才免语言低担保 赴美带薪读研！— </span></a></li></ul>
<br/><br/><br/>
              ]]>
            </description>
            <pubDate>Tue, 09 Oct 2018 20:17:08 +0800</pubDate>
            <link>https://www.iteye.com/blog/user/java8988/blog/2431885</link>
            <guid isPermaLink="false">https://www.iteye.com/blog/user/java8988/blog/2431885</guid>
          </item>
                  <item>
            <title>架构师成长之路</title>
            <description>
              <![CDATA[
              <div class="iteye-blog-content-contain" style="font-size: 14px;">
<blockquote>
<blockquote style="padding: 20px; margin: 0px 0px 25px; font-size: 16px; border-left-width: 6px; border-left-color: #b4b4b4; background-color: #f7f7f7; line-height: 30px;">
<p style="margin-bottom: 25px; line-height: 1.7;">想要成为架构师，对技术的深度和广度都有很高的要求，本文列举出成为一个架构师必备的技能和学习路线。<br>对于学习途径有疑惑或苦恼，或者有优秀资料可以提供的同学，可加微信，共同交流学习 </p>
<div class="image-package" style="padding-bottom: 25px; width: auto; margin-left: 0px; text-align: center;">
<div class="image-container" style="background-color: transparent; margin: 0px auto; max-width: 430px;">
<div class="image-view" style="width: 430px; height: 430px; overflow: hidden;"><img alt="" src="https://upload-images.jianshu.io/upload_images/11336294-15ef066c7738d406.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/430/format/webp"></div>
</div>
<div class="image-caption" style="min-width: 20%; max-width: 80%; display: inline-block; padding: 10px; margin: 0px auto; border-bottom: 1px solid #d9d9d9; font-size: 14px; color: #969696; line-height: 1.7;">wx_qcode.jpg</div>
</div>
</blockquote>
<h1 style="font-size: 26px; margin-bottom: 15px; font-family: inherit; line-height: 1.7; color: #2f2f2f;">1. 阅读源码</h1>
<p style="margin-bottom: 25px;">说到阅读源码，可能很多同学都尝试过去阅读一些开源框架的源码，但是很难找到一个入口点；即便找到入口点，又会觉得源码中好绕，看着看着把自己都看晕了。其实，阅读源码是需要基础的。开源框架的源码中都使用了大量的设计模式，所以在阅读源码之前，我们首先要熟悉常见的设计模式</p>
<h2 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 24px;">1.1 常用设计模式</h2>
<ul>
<li style="line-height: 30px;">Proxy 代理模式</li>
<li style="line-height: 30px;">Factory 工厂模式
<ul style="margin-top: 15px; margin-bottom: 20px; margin-left: 20px;">
<li style="line-height: 30px;">简单工厂模式</li>
<li style="line-height: 30px;">工厂方法模式</li>
<li style="line-height: 30px;">抽象工厂模式</li>
</ul>
</li>
<li style="line-height: 30px;">Singleton 单例模式</li>
<li style="line-height: 30px;">Delegate 委派模式</li>
<li style="line-height: 30px;">Strategy 策略模式</li>
<li style="line-height: 30px;">Prototype 原型模式</li>
<li style="line-height: 30px;">Template 模板模式</li>
</ul>
<blockquote style="padding: 20px; margin: 0px 0px 25px; font-size: 16px; border-left-width: 6px; border-left-color: #b4b4b4; background-color: #f7f7f7; line-height: 30px;">
<p style="line-height: 1.7;">推荐书籍<br>《大话设计模式》 程杰 著</p>
</blockquote>
<h2 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 24px;">1.2 Spring源码走读</h2>
<p style="margin-bottom: 25px;">Spring 源码主要又分为一下几大块：</p>
<h3 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 22px;">1.2.1 spring-beans包</h3>
<ul>
<li style="line-height: 30px;">接口示例化</li>
<li style="line-height: 30px;">代理Bean操作</li>
</ul>
<h3 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 22px;">1.2.2 spring-context包</h3>
<ul>
<li style="line-height: 30px;">IOC容器设计原理及高级特性</li>
<li style="line-height: 30px;">AOP设计原理</li>
<li style="line-height: 30px;">FactoryBean与BeanFactory</li>
</ul>
<h3 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 22px;">1.2.3 spring-tx包</h3>
<ul>
<li style="line-height: 30px;">声明式事务底层原理</li>
<li style="line-height: 30px;">Spring事务处理机制</li>
<li style="line-height: 30px;">事务的传播与监控</li>
<li style="line-height: 30px;">基于SpringJDBC手写ORM框架</li>
</ul>
<h3 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 22px;">1.2.4 spring-webmvc</h3>
<ul>
<li style="line-height: 30px;">MVC原理介绍</li>
<li style="line-height: 30px;">与IOC容器整合原理</li>
<li style="line-height: 30px;">HandlerMapping实现原理</li>
<li style="line-height: 30px;">HandlerAdapter实现原理</li>
<li style="line-height: 30px;">ViewResolver实现原理</li>
<li style="line-height: 30px;">Controller实现原理</li>
<li style="line-height: 30px;">动态参数匹配原理</li>
<li style="line-height: 30px;">SpringMVC与Struts2对比分析</li>
<li style="line-height: 30px;">手写实现SpringMVC框架</li>
</ul>
<h3 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 22px;">1.2.5 Spring5新特性</h3>
<ul>
<li style="line-height: 30px;">Spring 5.x的兼容性</li>
<li style="line-height: 30px;">分析自带通用日志框架</li>
<li style="line-height: 30px;">多序列化数据格式绑定API</li>
<li style="line-height: 30px;">函数式风格的ApplicationContext</li>
<li style="line-height: 30px;">Kotlin表达式的支持</li>
<li style="line-height: 30px;">WebFlux模块介绍</li>
<li style="line-height: 30px;">Testing改进</li>
</ul>
<blockquote style="padding: 20px; margin: 0px 0px 25px; font-size: 16px; border-left-width: 6px; border-left-color: #b4b4b4; background-color: #f7f7f7; line-height: 30px;">
<p style="line-height: 1.7;">阅读指引<br><a href="https://www.jianshu.com/p/5085c1ff3e57" style="background-color: transparent; color: #3194d0; cursor: pointer;" target="_blank">spring源码学习 - 一个简单bean的实例化过程</a><br><a href="https://www.jianshu.com/p/d0e5f4805880" style="background-color: transparent; color: #3194d0; cursor: pointer;" target="_blank">spring源码学习 - 注解bean的解析注册过程</a></p>
</blockquote>
<h2 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 24px;">1.3 MyBatis</h2>
<ul>
<li style="line-height: 30px;">代码自动生成器：Generator</li>
<li style="line-height: 30px;">MyBatis下1对多，多对多嵌套结果、嵌套查询</li>
<li style="line-height: 30px;">一级缓存、二级缓存使用场景及选择策略</li>
<li style="line-height: 30px;">MyBatis与Spring集成spring-mybatis.jar分析</li>
<li style="line-height: 30px;">Spring集成下的SqlSession与Mapper</li>
<li style="line-height: 30px;">MyBatis的事务</li>
<li style="line-height: 30px;">分析MyBatis的动态代理的真正实现</li>
<li style="line-height: 30px;">一步一步手写实现MyBatis 1.0到2.0</li>
</ul>
<h1 style="font-size: 26px; margin-bottom: 15px; font-family: inherit; line-height: 1.7; color: #2f2f2f;">2. 分布式架构</h1>
<h2 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 24px;">2.1 漫谈分布式架构</h2>
<ul>
<li style="line-height: 30px;">初识分布式架构及意义</li>
<li style="line-height: 30px;">如何把应用从单机扩展分布式</li>
<li style="line-height: 30px;">大型分布式架构演进过程</li>
<li style="line-height: 30px;">构建分布式架构最重要因素
<ul style="margin-top: 15px; margin-bottom: 20px; margin-left: 20px;">
<li style="line-height: 30px;">CDN加速静态文件访问</li>
<li style="line-height: 30px;">分布式存储</li>
<li style="line-height: 30px;">分布式搜索引擎</li>
<li style="line-height: 30px;">应用发布与监控</li>
<li style="line-height: 30px;">应用容灾及机房规划</li>
<li style="line-height: 30px;">系统动态扩容</li>
</ul>
</li>
<li style="line-height: 30px;">分布式架构设计
<ul style="margin-top: 15px; margin-bottom: 20px; margin-left: 20px;">
<li style="line-height: 30px;">主流架构模型-SOA架构和微服务架构</li>
<li style="line-height: 30px;">领域驱动设计及业务驱动划分</li>
<li style="line-height: 30px;">分布式架构的基本理论CAP、BASE以及其应用</li>
<li style="line-height: 30px;">什么是分布式架构下的高可用设计</li>
<li style="line-height: 30px;">分布式架构下的可伸缩设计</li>
<li style="line-height: 30px;">构建高性能的分布式架构</li>
</ul>
</li>
</ul>
<h2 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 24px;">2.2 分布式架构策略-分而治之</h2>
<ul>
<li style="line-height: 30px;">从简到难，从网络通信探究分布式通信的原理</li>
<li style="line-height: 30px;">基于消息方式的系统间通信</li>
<li style="line-height: 30px;">理解通信协议传输过程中的序列化和反序列化机制</li>
<li style="line-height: 30px;">基于框架的RPC通信技术
<ul style="margin-top: 15px; margin-bottom: 20px; margin-left: 20px;">
<li style="line-height: 30px;">WebService/Apache CXF</li>
<li style="line-height: 30px;">RMI/Spring RMI</li>
<li style="line-height: 30px;">Hessian</li>
</ul>
</li>
<li style="line-height: 30px;">传统RPC技术在大型分布式架构下面临的问题</li>
<li style="line-height: 30px;">分布式架构下的RPC解决方案</li>
<li style="line-height: 30px;">分布式系统的基石-Zookeeper、
<ul style="margin-top: 15px; margin-bottom: 20px; margin-left: 20px;">
<li style="line-height: 30px;">从0开始搭建3个节点的zookeeper集群</li>
<li style="line-height: 30px;">深入分析Zookeeper在disconf配置中心的应用</li>
<li style="line-height: 30px;">基于Zookeeper的分布式锁解决方案</li>
<li style="line-height: 30px;">Zookeeper Watcher 核心机制深入源码分析</li>
<li style="line-height: 30px;">Zookeeper集群升级、迁移</li>
<li style="line-height: 30px;">基于Zookeeper实现分布式服务器动态上下线感知</li>
<li style="line-height: 30px;">深入分析Zookeeper Zab协议及选举机制源码解读</li>
</ul>
</li>
<li style="line-height: 30px;">使用dubbo对单一应用服务化改造
<ul style="margin-top: 15px; margin-bottom: 20px; margin-left: 20px;">
<li style="line-height: 30px;">dubbo管理中心及监控平台安装部署</li>
<li style="line-height: 30px;">dubbo分布式服务模块划分(领域驱动)</li>
<li style="line-height: 30px;">基于dubbo分布式系统架构实践</li>
<li style="line-height: 30px;">dubbo负载均衡策略分析</li>
<li style="line-height: 30px;">dubbo服务调试之服务只订阅及服务只注册配置</li>
<li style="line-height: 30px;">dubbo服务接口的设计原则(实战经验分享)</li>
<li style="line-height: 30px;">dubbo设计原理及源码分析</li>
<li style="line-height: 30px;">基于dubbo构建大型分布式电商平台实战雏形</li>
<li style="line-height: 30px;">dubbo容错机制及高扩展性分析</li>
</ul>
</li>
</ul>
<h2 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 24px;">2.3 分布式架构-中间件</h2>
<h3 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 22px;">2.3.1 消息中间件(分布式消息通信)</h3>
<h4 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 20px;">2.3.1.1 消息中间件在分布式框架中的应用</h4>
<h4 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 20px;">2.3.1.2 消息中间件ActiveMQ</h4>
<ul>
<li style="line-height: 30px;">ActiveMQ高可用集群企业级部署方案</li>
<li style="line-height: 30px;">ActiveMQ P2P及PUB/SUB模型详解</li>
<li style="line-height: 30px;">ActiveMQ消息确认及重发策略</li>
<li style="line-height: 30px;">ActiveMQ基于Spring完成分布式消息队列实战</li>
</ul>
<h4 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 20px;">2.3.1.3 消息中间件Kafka</h4>
<ul>
<li style="line-height: 30px;">Kafka基于Zookeeper搭建高可用集群实践</li>
<li style="line-height: 30px;">Kafka消息处理过程剖析</li>
<li style="line-height: 30px;">Java客户端实现Kafka生产者与消费者实例</li>
<li style="line-height: 30px;">Kafka的副本机制及选举原理剖析</li>
<li style="line-height: 30px;">基于Kafka实现应用日志实时上报统计分析</li>
</ul>
<h4 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 20px;">2.3.1.4 消息中间件RabbitMQ</h4>
<ul>
<li style="line-height: 30px;">初步认识RabbitMQ及高可用集群部署</li>
<li style="line-height: 30px;">详解RabbitMQ消息分发机制及主题消息分发</li>
<li style="line-height: 30px;">RabbitMQ消息路由机制分析</li>
<li style="line-height: 30px;">RabbitMQ消息确认机制</li>
</ul>
<h3 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 22px;">2.3.2 分布式缓存(Redis)</h3>
<ul>
<li style="line-height: 30px;">从入门到精通，Redis的数据结构分析</li>
<li style="line-height: 30px;">Redis主从复制原理及无磁盘复制分析</li>
<li style="line-height: 30px;">Redis管道模式详解</li>
<li style="line-height: 30px;">Redis缓存与数据库一致性问题解决方案</li>
<li style="line-height: 30px;">基于Redis实现分布式锁</li>
<li style="line-height: 30px;">图解Redis中的AOF和RDB持久化策略的原理</li>
<li style="line-height: 30px;">Redis读写分离架构实践</li>
<li style="line-height: 30px;">Redis烧饼架构及数据丢失问题分析</li>
<li style="line-height: 30px;">Redis Cluster 数据分布算法之Hash slot</li>
<li style="line-height: 30px;">使用Redis常见问题及性能优化思路</li>
<li style="line-height: 30px;">Redis高可用及高伸缩架构实战</li>
<li style="line-height: 30px;">缓存击穿、缓存雪崩预防策略</li>
<li style="line-height: 30px;">Redis批量查询优化</li>
<li style="line-height: 30px;">Redis高性能集群之twemproxy or codis</li>
</ul>
<h3 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 22px;">2.3.3 数据存储</h3>
<h4 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 20px;">2.3.3.1 非结构化数据NoSQL</h4>
<ul>
<li style="line-height: 30px;">NoSQL简介及MongoDB基本概念</li>
<li style="line-height: 30px;">MongoDB支持的数据类型分析</li>
<li style="line-height: 30px;">MongoDB可视化客户端及Java API实践</li>
<li style="line-height: 30px;">手写基于MongoDB的ORM框架</li>
<li style="line-height: 30px;">MongoDB企业级集群解决方案</li>
<li style="line-height: 30px;">MongoDB聚合、索引及基本执行命令</li>
<li style="line-height: 30px;">MongoDB数据分析 、转存及恢复策略</li>
</ul>
<h4 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 20px;">2.3.3.2 mysql数据库</h4>
<ul>
<li style="line-height: 30px;">MySQL主从符合及读写分离实战</li>
<li style="line-height: 30px;">MySQL + keepalived实现双主高可用方案实践</li>
<li style="line-height: 30px;">MySQL 高性能解决方案之分库分表</li>
</ul>
<h4 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 20px;">2.3.3.3 分库分表中间件(Mycat)</h4>
<ul>
<li style="line-height: 30px;">初识数据库中间件Mycat</li>
<li style="line-height: 30px;">基于Mycat实现mysql数据库读写分离</li>
<li style="line-height: 30px;">基于Mycat实战之数据库切分策略剖析</li>
<li style="line-height: 30px;">Mycat全局表、ER表、分片策略分析</li>
</ul>
<h3 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 22px;">2.3.4 后台服务</h3>
<ul>
<li style="line-height: 30px;">基于OpenResty部署应用层Nginx以及Nginx+lua实践</li>
<li style="line-height: 30px;">Nginx反向代理服务器及负载均衡服务配置实战</li>
<li style="line-height: 30px;">利用keepalived + Nginx实践Nginx高可用方案</li>
<li style="line-height: 30px;">基于Nginx实现访问控制、连接限制</li>
<li style="line-height: 30px;">Nginx动静分离实战</li>
<li style="line-height: 30px;">Nginx Location、Rewrite等语法配置及原理分析</li>
<li style="line-height: 30px;">Nginx提供https服务</li>
<li style="line-height: 30px;">基于Nginx+lua完成访问流量实时上报kafka的实战</li>
</ul>
<h3 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 22px;">2.3.5 高性能的NIO框架(Netty)</h3>
<ul>
<li style="line-height: 30px;">IO的基本概念、NIO、AIO、BIO深入分析</li>
<li style="line-height: 30px;">NIO的核心设计思想</li>
<li style="line-height: 30px;">Netty产生的背景及应用场景分析</li>
<li style="line-height: 30px;">基于Netty实现高性能IM聊天工具</li>
<li style="line-height: 30px;">基于Netty实现Dubbo多协议通信支持</li>
<li style="line-height: 30px;">Netty无锁化串行设计及高并发处理机制</li>
<li style="line-height: 30px;">手写实现多协议RPC框架</li>
</ul>
<h2 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 24px;">2.4 分布式解决方案</h2>
<ul>
<li style="line-height: 30px;">分布式全局ID生成方案</li>
<li style="line-height: 30px;">session跨域共享及企业级单点登录解决方案实战</li>
<li style="line-height: 30px;">分布式事务解决方案实战</li>
<li style="line-height: 30px;">高并发下的服务降级、限流</li>
<li style="line-height: 30px;">基于分布式架构下分布式锁的解决方案</li>
<li style="line-height: 30px;">分布式架构下实现分布式定时调度</li>
</ul>
<blockquote style="padding: 20px; margin: 0px 0px 25px; font-size: 16px; border-left-width: 6px; border-left-color: #b4b4b4; background-color: #f7f7f7; line-height: 30px;">
<p style="line-height: 1.7;">推荐书籍<br>《大型网站系统与Java中间件实践》曾宪杰 著<br>《分布式服务框架原理与实践》 李林峰 著</p>
</blockquote>
<h1 style="font-size: 26px; margin-bottom: 15px; font-family: inherit; line-height: 1.7; color: #2f2f2f;">3. 微服务架构</h1>
<h2 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 24px;">3.1 微框架(Spring Boot)</h2>
<ul>
<li style="line-height: 30px;">Spring Boot与微服务之间的关系</li>
<li style="line-height: 30px;">Spring Boot热部署实战</li>
<li style="line-height: 30px;">核心组件之starter、actuator、auto-configuration、cli</li>
<li style="line-height: 30px;">Spring Boot集成MyBatis实现多数据源路由实战</li>
<li style="line-height: 30px;">Spring Boot集成Dubbo实战</li>
<li style="line-height: 30px;">Spring Boot 集成Redis实战</li>
<li style="line-height: 30px;">Spring Boot集成Swagger2 构建API管理及测试体系</li>
<li style="line-height: 30px;">Spring Boot实现多环境配置动态解析</li>
</ul>
<h2 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 24px;">3.2 Spring Cloud</h2>
<ul>
<li style="line-height: 30px;">Eureka注册中心</li>
<li style="line-height: 30px;">Ribbon集成REST实现负载均衡</li>
<li style="line-height: 30px;">Fegion声明式服务调用</li>
<li style="line-height: 30px;">Hystrix服务熔断降级方式</li>
<li style="line-height: 30px;">Zuul实现微服务网关</li>
<li style="line-height: 30px;">Config分布式统一配置中心</li>
<li style="line-height: 30px;">Sleuth调用链路跟踪</li>
<li style="line-height: 30px;">BUS消息总线</li>
<li style="line-height: 30px;">基于Hystrix实现接口降级实战</li>
<li style="line-height: 30px;">Spring Boot集成Spring Cloud实现统一整合分离</li>
</ul>
<h2 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 24px;">3.3 Docker虚拟化</h2>
<ul>
<li style="line-height: 30px;">了解Docker的镜像、仓库、容器</li>
<li style="line-height: 30px;">Dockerfile构建LNMP环境部署个人博客wordpress</li>
<li style="line-height: 30px;">Docker Compose构建LNMP环境部署个人博客wordpress</li>
<li style="line-height: 30px;">Docker网络组成、路由互联、openvswitch</li>
<li style="line-height: 30px;">基于swarm构建Docker集群实战</li>
<li style="line-height: 30px;">Kubernetes简介</li>
</ul>
<h2 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 24px;">3.4 漫谈微服务架构</h2>
<ul>
<li style="line-height: 30px;">SOA架构和微服务架构之间的区别与联系</li>
<li style="line-height: 30px;">如何设计微服务及其设计原则</li>
<li style="line-height: 30px;">解惑Spring Boot流行因素及能够解决什么问题</li>
<li style="line-height: 30px;">什么是Spring Cloud，为何要选择Spring Cloud</li>
<li style="line-height: 30px;">基于全局分析Spring Cloud各个组件所解决的问题</li>
</ul>
<blockquote style="padding: 20px; margin: 0px 0px 25px; font-size: 16px; border-left-width: 6px; border-left-color: #b4b4b4; background-color: #f7f7f7; line-height: 30px;">
<p style="line-height: 1.7;">推荐书籍<br>《Spring Cloud与Docker微服务架构实战》周立 著</p>
</blockquote>
<h1 style="font-size: 26px; margin-bottom: 15px; font-family: inherit; line-height: 1.7; color: #2f2f2f;">4. 并发编程</h1>
<h2 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 24px;">4.1 Java 内存模型(JMM)</h2>
<ul>
<li style="line-height: 30px;">线程通信</li>
<li style="line-height: 30px;">消息传递</li>
</ul>
<h2 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 24px;">4.2 内存模型</h2>
<ul>
<li style="line-height: 30px;">指令重排序</li>
<li style="line-height: 30px;">顺序一致性</li>
<li style="line-height: 30px;">happens-before</li>
<li style="line-height: 30px;">as-if-serial</li>
</ul>
<h2 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 24px;">4.3 synchronized</h2>
<ul>
<li style="line-height: 30px;">同步、重量级锁</li>
<li style="line-height: 30px;">synchronized原理</li>
<li style="line-height: 30px;">锁优化
<ul style="margin-top: 15px; margin-bottom: 20px; margin-left: 20px;">
<li style="line-height: 30px;">自旋锁</li>
<li style="line-height: 30px;">轻量级锁</li>
<li style="line-height: 30px;">重量级锁</li>
<li style="line-height: 30px;">偏向锁</li>
</ul>
</li>
</ul>
<h2 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 24px;">4.4 volatile</h2>
<ul>
<li style="line-height: 30px;">volatile 实现机制</li>
<li style="line-height: 30px;">内存语义</li>
<li style="line-height: 30px;">内存模型</li>
</ul>
<h2 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 24px;">4.5 DCL(Double Check Lock)</h2>
<ul>
<li style="line-height: 30px;">单例模式</li>
<li style="line-height: 30px;">DCL(双检锁)</li>
<li style="line-height: 30px;">解决方案</li>
</ul>
<h2 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 24px;">4.6 并发基础</h2>
<ul>
<li style="line-height: 30px;">AQS
<ul style="margin-top: 15px; margin-bottom: 20px; margin-left: 20px;">
<li style="line-height: 30px;">AbstractQueuedSynchronizer同步器</li>
<li style="line-height: 30px;">CLH同步队列</li>
<li style="line-height: 30px;">同步状态的获取和释放</li>
<li style="line-height: 30px;">线程阻塞和唤醒</li>
</ul>
</li>
<li style="line-height: 30px;">CAS
<ul style="margin-top: 15px; margin-bottom: 20px; margin-left: 20px;">
<li style="line-height: 30px;">Compare And Swap</li>
<li style="line-height: 30px;">缺陷</li>
</ul>
</li>
</ul>
<h2 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 24px;">4.7 锁</h2>
<ul>
<li style="line-height: 30px;">ReentrantLoak 可重入锁</li>
<li style="line-height: 30px;">ReentrantLockReadWriteLock 可重入读写锁</li>
<li style="line-height: 30px;">Condition</li>
</ul>
<h2 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 24px;">4.8 并发工具类</h2>
<ul>
<li style="line-height: 30px;">CyclicBarrier</li>
<li style="line-height: 30px;">CountDownLatch</li>
<li style="line-height: 30px;">Semphore</li>
</ul>
<h2 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 24px;">4.9 并发集合</h2>
<ul>
<li style="line-height: 30px;">ConcurrentHashMap</li>
<li style="line-height: 30px;">ConcurrentLinkedQueue</li>
</ul>
<h2 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 24px;">4.10 原子操作</h2>
<ul>
<li style="line-height: 30px;">基本类型
<ul style="margin-top: 15px; margin-bottom: 20px; margin-left: 20px;">
<li style="line-height: 30px;">AtomicBoolean</li>
<li style="line-height: 30px;">AtomicInteger</li>
<li style="line-height: 30px;">AtomicLong</li>
</ul>
</li>
<li style="line-height: 30px;">数组
<ul style="margin-top: 15px; margin-bottom: 20px; margin-left: 20px;">
<li style="line-height: 30px;">AtomicIntegerArray</li>
<li style="line-height: 30px;">AtomicLongArray</li>
<li style="line-height: 30px;">AtomicReferenceArray</li>
</ul>
</li>
<li style="line-height: 30px;">引用类型
<ul style="margin-top: 15px; margin-bottom: 20px; margin-left: 20px;">
<li style="line-height: 30px;">AtomicReference</li>
<li style="line-height: 30px;">AtomicReferenceFieldUpdater</li>
</ul>
</li>
</ul>
<h2 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 24px;">4.11 线程池</h2>
<ul>
<li style="line-height: 30px;">Executor</li>
<li style="line-height: 30px;">ThreadPoolExecutor</li>
<li style="line-height: 30px;">CallableFuture</li>
<li style="line-height: 30px;">ScheduledExecutorService</li>
</ul>
<h2 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 24px;">4.12 其他</h2>
<ul>
<li style="line-height: 30px;">TheadLocal</li>
<li style="line-height: 30px;">Fork/Join</li>
</ul>
<blockquote style="padding: 20px; margin: 0px 0px 25px; font-size: 16px; border-left-width: 6px; border-left-color: #b4b4b4; background-color: #f7f7f7; line-height: 30px;">
<p style="line-height: 1.7;">推荐书籍<br>《深入理解Java虚拟机》周志明 著<br>《实战Java高并发程序设计》 葛一鸣 郭超 编著 <span style="font-weight: bold;">墙裂推荐</span><br>《Java并发编程实战》Brian Goetz/ Tim Peierls/ Joshua Bloch/ Joseph Bowbeer/ David Holmes/ Doug Lea 著 董云兰等译</p>
</blockquote>
<h1 style="font-size: 26px; margin-bottom: 15px; font-family: inherit; line-height: 1.7; color: #2f2f2f;">5. 性能优化</h1>
<h2 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 24px;">5.1 理解性能优化</h2>
<ul>
<li style="line-height: 30px;">性能基准</li>
<li style="line-height: 30px;">性能优化到底是什么</li>
<li style="line-height: 30px;">衡量维度</li>
</ul>
<h2 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 24px;">5.2 JVM调优</h2>
<ul>
<li style="line-height: 30px;">知其然，知其所以然</li>
<li style="line-height: 30px;">什么是JVM运行时数据区</li>
<li style="line-height: 30px;">什么是JVM内存模型JMM</li>
<li style="line-height: 30px;">各种垃圾回收器使用场景(throughput\CMS)</li>
<li style="line-height: 30px;">理解GC日志，从日志看端倪</li>
<li style="line-height: 30px;">实战MAT分析dump文件</li>
</ul>
<h2 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 24px;">5.3 Tomcat调优篇</h2>
<ul>
<li style="line-height: 30px;">分析Tomcat线程模型</li>
<li style="line-height: 30px;">Tomcat系统参数认识及调优</li>
<li style="line-height: 30px;">基准测试</li>
</ul>
<h2 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 24px;">5.4 MySQL调优</h2>
<ul>
<li style="line-height: 30px;">理解MySQL低层B+Tree机制</li>
<li style="line-height: 30px;">SQL执行计划详解</li>
<li style="line-height: 30px;">索引优化详解</li>
<li style="line-height: 30px;">SQL语句优化</li>
</ul>
<h1 style="font-size: 26px; margin-bottom: 15px; font-family: inherit; line-height: 1.7; color: #2f2f2f;">6. 团队协作效率</h1>
<h2 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 24px;">6.1 Maven</h2>
<ul>
<li style="line-height: 30px;">生成可执行jar、理解Scope生产呢过最精确的jar</li>
<li style="line-height: 30px;">解决类冲突、包依赖 NoClassDefFoundError问题定位及解决</li>
<li style="line-height: 30px;">全面理解Maven的Lifecycle\Phase\Goal</li>
<li style="line-height: 30px;">架构师必备之Maven生成Archetype</li>
<li style="line-height: 30px;">Maven流行插件实战、手写自己的插件</li>
<li style="line-height: 30px;">Nexus使用、上传、配置</li>
<li style="line-height: 30px;">对比Gradle</li>
</ul>
<h2 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 24px;">6.2 Jenkins</h2>
<p style="margin-bottom: 25px;">持续集成，一次build解决所有手动工作</p>
<h2 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 24px;">6.3 Sonar</h2>
<p style="margin-bottom: 25px;">减少人为疏漏，静态代码检查，让你的代码更健壮</p>
<h2 style="font-family: inherit; line-height: 1.7; color: #2f2f2f; margin-bottom: 15px; font-size: 24px;">6.4 Git</h2>
<ul>
<li style="line-height: 30px;">什么是git以及git的工作原理</li>
<li style="line-height: 30px;">git常用命令best practise(避坑教学)</li>
<li style="line-height: 30px;">git冲突怎么引起的，如何解决</li>
<li style="line-height: 30px;">架构师职责：git flow规范团队git使用规程</li>
<li style="line-height: 30px;">团队案例分享(买不到才是最贵的)</li>
</ul>
<h1 style="font-size: 26px; margin-bottom: 15px; font-family: inherit; line-height: 1.7; color: #2f2f2f;">7. 项目实战</h1>
<p style="margin-bottom: 25px;">未完待续...</p>
<blockquote style="padding: 20px; margin: 0px 0px 25px; font-size: 16px; border-left-width: 6px; border-left-color: #b4b4b4; background-color: #f7f7f7; line-height: 30px;">
<p style="line-height: 1.7;">其他书籍推荐：<br>《深入分析Java Web技术内幕》<br>《Java编程思想》<br>《Effective Java》<br>《重构 改善既有代码结构》<br>《高性能MySQL》</p>
</blockquote>
<div class="image-package">
<div class="image-container">
<div class="image-container-fill" style="padding-bottom: 258px;"> <img alt="" src="https://upload-images.jianshu.io/upload_images/11336294-1786e41e2b22ad34.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/258/format/webp">
</div>
</div>
<div class="image-caption"> </div>
</div>
</blockquote>
</div>
              
              <br/><br/>
              <span style="color:red;">
                <a href="https://www.iteye.com/blog/java8988-2429874#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
              </span>
              <br/><br/><br/>
<span style="color:#E28822;">ITeye推荐</span>
<br/>
<ul><li><a href='/clicks/433' target='_blank'><span style="color:red;font-weight:bold;">—软件人才免语言低担保 赴美带薪读研！— </span></a></li></ul>
<br/><br/><br/>
              ]]>
            </description>
            <pubDate>Sat, 01 Sep 2018 00:59:29 +0800</pubDate>
            <link>https://www.iteye.com/blog/user/java8988/blog/2429874</link>
            <guid isPermaLink="false">https://www.iteye.com/blog/user/java8988/blog/2429874</guid>
          </item>
                  <item>
            <title>面试常问之TCP与UDP</title>
            <description>
              <![CDATA[
              <div class="iteye-blog-content-contain" style="font-size: 14px;">
<p>原文地址：<a href="https://www.jianshu.com/p/deee6abf0b72" title="原文链接" target="_blank">https://www.jianshu.com/p/deee6abf0b72</a> 转载请注明出处</p>
<p> </p>
<p>TCP: 传输控制协议（英语：Transmission Control Protocol，缩写为TCP）是一种面向连接的、可靠的、基于字节流的传输层通信协议，由IETF的RFC 793定义。</p>
<p>UDP:用户数据报协议（英语：User Datagram Protocol，缩写为UDP），又称使用者资料包协定，是一个简单的面向数据报的传输层协议，正式规范为RFC 768。</p>
<h1>共同点</h1>
<ul>
<li style="line-height: 30px;">传输层协议</li>
</ul>
<h1>不同点</h1>
<ul>
<li style="line-height: 30px;">
<p style="margin-bottom: 25px; overflow: visible;">UDP 继承 IP 的特性，不保证不丢失，不保证按顺序到达。TCP 就是提供可靠的数据，无差错、不丢失、不重复、按循序到达。</p>
</li>
<li style="line-height: 30px;">
<p style="margin-bottom: 25px; overflow: visible;">TCP提供有保证的数据传输，而UDP不提供</p>
<blockquote style="padding: 20px; margin: 0px 0px 25px; border-left-width: 6px; border-left-color: #b4b4b4; background-color: #f7f7f7; line-height: 30px;">
<p style="overflow: visible; line-height: 1.7;">这意味着TCP有一个特殊的机制来确保数据安全的不出错的从一个端点传到另一个端点，而UDP不提供任何这样的保证。</p>
</blockquote>
</li>
<li style="line-height: 30px;">
<p style="margin-bottom: 25px; overflow: visible;">TCP是面向链接的，虽然说网络的不安全不稳定特性决定了多少次握手都不能保证连接的可靠性， 但TCP的三次握手在最低限度上（实际上也很大程度上保证了）保证了连接的可靠性；</p>
</li>
<li style="line-height: 30px;">
<p style="margin-bottom: 25px; overflow: visible;">UDP不是面向连接的，UDP传送数据前并不与对方建立连接，对接收到的数据也不发送确认信号， 发送端不知道数据是否会正确接收，当然也不用重发，所以说UDP是无连接的、不可靠的一种数据传输协议</p>
</li>
</ul>
<blockquote>
<p style="margin-bottom: 25px; line-height: 1.7;">也正由于上面的特点，使得UDP的开销更小数据传输速率更高，因为不必进行收发数据的确认，所以UDP的实时性更好。</p>
<p style="margin-bottom: 25px; line-height: 1.7;">所以采用TCP传输协议的MSN比采用UDP的QQ传输文件慢</p>
<p style="line-height: 1.7;">但并不能说QQ的通信是不安全的，因为程序员可以手动对UDP的数据收发进行验证， 比如发送方对每个数据包进行编号然后由接收方进行验证啊什么的</p>
</blockquote>
<ul>
<li style="line-height: 30px;">
<p style="margin-bottom: 25px; overflow: visible;">UDP 是数据格式基于数据报，一个一个的发，一个一个的收。TCP 是面向字节流，发送的是一个流数据。</p>
</li>
<li style="line-height: 30px;">
<p style="margin-bottom: 25px; overflow: visible;">UDP 是不处理堵塞，应用需要发，就会发送。TCP 还拥有堵塞控制，TCP 会根据网络环境调整发包的频率。</p>
</li>
<li style="line-height: 30px;">
<p style="margin-bottom: 25px; overflow: visible;">UDP 支持多播和广播</p>
</li>
</ul>
<p>TCP、UDP对比</p>
<table class="bbcode" style="table-layout: fixed; min-width: 400px; max-width: 650px;">
<tr>
<td> </td>
<td>TCP</td>
<td>UDP</td>
</tr>
<tr>
<td>可靠性</td>
<td>可靠</td>
<td>不可靠</td>
</tr>
<tr>
<td> 连接性</td>
<td> 面向连接</td>
<td> 无连接</td>
</tr>
<tr>
<td> 报文</td>
<td> 面向字节流</td>
<td> 面向报文</td>
</tr>
<tr>
<td> 效率</td>
<td> 传输效率低</td>
<td> 传输效率高</td>
</tr>
<tr>
<td> 双工性</td>
<td> 全双工</td>
<td> 一对一、一对多、多对一、多对多</td>
</tr>
<tr>
<td> 流量控制</td>
<td> 有(滑动窗口)</td>
<td> 无</td>
</tr>
<tr>
<td> 拥塞控制</td>
<td> 有(慢开始、拥塞避免、快重传、快恢复)</td>
<td> 无</td>
</tr>
</table>
<h1>
<br> TCP和UDP协议的一些应用</h1>
<div class="image-package">
<div class="image-container" style="background-color: transparent; margin: 0px auto; max-width: 590px;">
<div class="image-view" style="width: 590px; height: 489.984px; overflow: hidden;"><img alt="" src="https://upload-images.jianshu.io/upload_images/11336294-2dadb5b4f34330f9.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/590/format/webp"></div>
</div>
<div class="image-caption" style="min-width: 20%; max-width: 80%; display: inline-block; padding: 10px; margin: 0px auto; border-bottom: 1px solid #d9d9d9; font-size: 14px; color: #969696; line-height: 1.7;">image</div>
</div>
<h1>引申</h1>
<h2>TCP三次握手</h2>
<p>TCP 是面向连接的，数据通信之前必须要建立连接，这个连接可以是 1 对多。</p>
<h3>TCP 三次握手的过程</h3>
<div class="image-package">
<div class="image-container" style="background-color: transparent; margin: 0px auto; max-width: 607px;">
<div class="image-container-fill"> </div>
<div class="image-view" style="width: 607px; height: 410.984px; overflow: hidden;"><img alt="" src="https://upload-images.jianshu.io/upload_images/11336294-ad7af850e7b9c993.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/607/format/webp"></div>
</div>
<div class="image-caption" style="min-width: 20%; max-width: 80%; display: inline-block; padding: 10px; margin: 0px auto; border-bottom: 1px solid #d9d9d9; font-size: 14px; color: #969696; line-height: 1.7;">image</div>
</div>
<p>上图展示三次握手的流程图，文字描述过程如下： 客户端和服务端从 CLOSED 的状态变成在线状态。服务端需要处于 LISTEN. 1、客户端向服务端发起一个连接。报文中包含了： SYN = 1, 「序列号」的值， 发送之后客服端进入到 SYN-SENT 状态。</p>
<p>2、服务端接收到 SYN 和 序列号信息后，需要对这个报文进行的确认。服务端收到客户端发送过来的「序列号」的值，服务端会返回一个「确认号」的值（序列号+1）。同时返回 SYN = 1 表示还在同步阶段。 ACK = 1 表示确认号有意义。 序列号：表示服务端的序列号 y。 确认号：针对客户端发起连接的一个确认号。 服务端发送之后，进入到 SYN-RCVD 状态。</p>
<p>3、客户端接收到服务端返回的数据，使得客户端这一边的相关通信建立，并且同步了相关序列号和确认号的数值，但是服务端还没有接收到客户端回复的确认号。所以客户端需要再发送一个数据到服务端，主要包含： ACK = 1，这是确认号的数据有意义。 SYN = 0 序列号已经同步完成，不需要再同步序列号。 序列号：因为 SYN 已经不是第一次同步序列号的信息了。这个时候的序列号，就表示的是一个单纯的基于序列号最新的数据包的序列号。其值为：x+1。 确认号：返回服务端序列号 y 的确认号，为 y+1。 发送这个值之后，客户端进入到 ESTABLISHED 状态，服务端接受到这个值之后也进入到ESTABLISHED 状态。然后就可以开始传递数据通信了。</p>
<p>至此三次握手已经完成。</p>
<p><a href="https://www.jianshu.com/p/b0082662b22e" style="background-color: transparent; color: #3194d0; cursor: pointer;" target="_blank">通俗易懂的描述</a></p>
<h3>TCP 为什么进行是三次握手？</h3>
<p>为什么 TCP 需要进行三次握手，这个问题很多人的解释都引用了</p>
<blockquote>
<p style="line-height: 1.7;">为了防止已失效的连接请求报文段突然又传送到了服务端，因而产生错误。—— 谢希仁的《计算机网络》</p>
</blockquote>
<p>首先我们需要明白三次握手的意义在于什么，也就是说三次握手需要达到的一个目的是什么， 简单来说，其实是为了同步序列号和确认号的相关信息，而序列号和确认号又是保障数据的正确性以及窗口滑动机制的最基本的根据。所以我最需要明白的可能还是为什么要同步序列号就是为什么要三次握手：（举个例子来说明） 如果 A 给 B发送一个数据包，这个包由于网络的原因，很久才到 B 端，而这段时间，A 和 B 已经断开，并且重新建立了连接关系。没有相关同步序列号和确认号，B 端认为这个数据还是认为 A 这个时候要发给我的，但是其实这个数据上一次传输的数据，相当于这次传输的数据中插入了其他的数据，那么就会导致这次的数据出现异常。</p>
<h3>为什么不是两次</h3>
<p>对于 A 来看说，两次实现了信息一来一回，但是 TCP 的数据的可靠性，如果要实现对于 B 来说的信息的一来一回，那么第三次是一定要存在的。对两端的数据一来一回才是建立可靠连接的基本要求。</p>
<h3>为什么不是四次</h3>
<p>理论上其实这个同步序列号和确认号的过程，大于三次也不是没有的，应该说几十次上百次都是可以的，但是三次握手的过程已经实现了序号数据同步，在进行太多次的序号同步，已经没有意义。无故浪费宽带。</p>
<h2>TCP 四次挥手</h2>
<p>当通信完成，当然需要能够进行连接断开。</p>
<p>TCP 四层挥手的过程：</p>
<div class="image-package">
<div class="image-container" style="background-color: transparent; margin: 0px auto; max-width: 555px;">
<div class="image-container-fill"> </div>
<div class="image-view" style="width: 555px; height: 422px; overflow: hidden;"><img alt="" src="https://upload-images.jianshu.io/upload_images/11336294-c37aed26c7fe6008.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/555/format/webp"></div>
</div>
<div class="image-caption" style="min-width: 20%; max-width: 80%; display: inline-block; padding: 10px; margin: 0px auto; border-bottom: 1px solid #d9d9d9; font-size: 14px; color: #969696; line-height: 1.7;">image</div>
</div>
<p>1、任意一段（ A 端）发出一条 FIN 的数据。数据包含： FIN = 1, 序列号 A 端发出这个数据之后，进入到 FIN - WAIT -1 的状态，等待 B 端的回复.</p>
<p>2、B 收到 A 端的 FIN 的信息就回复一个数据，表示已经知道 A 端请求断开连接这个事情了。此时 B 端进入到 CLOSED - WAIT 的状态。A 端接收到这个数据进入到 FIN - WAIT -2 的状态。 数据中包含 ： ACK = 1 确认号</p>
<p>3、B 端给 A 端发起一次 FIN 的数据。请求结束连接，发送完成之后 B 端进入到 LAST - ACK 状态。发送的数据包含： FIN = 1; 序列号 ACK = 1; 确认号</p>
<p>4、 A 端接收到这个 B 端发送的 FIN 数据进入到 TIME- WAIT 状态，同时回复 B 端，已经接收到了 FIN 数据。回复的包中包含： ACK = 1; 确认号</p>
<h5>为什么需要设置一个 TIME-WAIT 的时间</h5>
<p><a href="https://blog.csdn.net/smileiam/article/details/78226816" style="background-color: transparent; color: #3194d0; cursor: pointer;" target="_blank">这个文章讲的特别好</a></p>
<blockquote>
<p style="line-height: 1.7;">一、保证TCP协议的全双工连接能够可靠关闭 先说第一点，如果Client直接CLOSED了，那么由于IP协议的不可靠性或者是其它网络原因，导致Server没有收到Client最后回复的ACK。那么Server就会在超时之后继续发送FIN，此时由于Client已经CLOSED了，就找不到与重发的FIN对应的连接，最后Server就会收到RST而不是ACK，Server就会以为是连接错误把问题报告给高层。这样的情况虽然不会造成数据丢失，但是却导致TCP协议不符合可靠连接的要求。所以，Client不是直接进入CLOSED，而是要保持TIME_WAIT，当再次收到FIN的时候，能够保证对方收到ACK，最后正确的关闭连接。</p>
</blockquote>
<blockquote>
<p style="line-height: 1.7;">二、保证这次连接的重复数据段从网络中消失 再说第二点，如果Client直接CLOSED，然后又再向Server发起一个新连接，我们不能保证这个新连接与刚关闭的连接的端口号是不同的。也就是说有可能新连接和老连接的端口号是相同的。一般来说不会发生什么问题，但是还是有特殊情况出现：假设新连接和已经关闭的老连接端口号是一样的，如果前一次连接的某些数据仍然滞留在网络中，这些延迟数据在建立新连接之后才到达Server，由于新连接和老连接的端口号是一样的，又因为TCP协议判断不同连接的依据是socket pair，于是，TCP协议就认为那个延迟的数据是属于新连接的，这样就和真正的新连接的数据包发生混淆了。所以TCP连接还要在TIME_WAIT状态等待2倍MSL，这样可以保证本次连接的所有数据都从网络中消失。</p>
</blockquote>
<h5>TCP 为什么进行是四次挥手？</h5>
<p>断开比连接更复杂，比较直接的理解是资源回收比资源分配会更麻烦。使得所有资源能够有效并且不产生错误的情况下释放。</p>
<p><code style="font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 12px; color: #c7254e; background-color: #f6f6f6; border-radius: 4px; padding: 2px 4px; border: none; white-space: pre-wrap; vertical-align: middle;">三次握手的本质是：将“四次握手”中的第二次、第三次握手合为一次，因为“四次握手”中的第二次、第三次握手都是由B向A传递报文，而且这两次发送报文的目的允许这两次报文合并为一次。</code>那么，TCP四次挥手中的第二次、第三次挥手，能否也能合为一次呢？</p>
<p>答案是否定的。将TCP四次挥手中的第二次、第三次挥手，合为一次。也就是将CLOSE_WAIT状态的停留时间变为0。然而，B之所以存在CLOSE_WAIT状态，是因为B可能还存在着需要发送给A但是未发送的数据，如果存在着这些数据，那么这个状态的时间，就是用来发送这些数据的，所以，TCP四次挥手中的第二次、第三次挥手无法合并为一次。所以，也就无法实现“TCP三次挥手”。<br>参考<br><a href="https://www.jianshu.com/p/74de8df5f686" style="background-color: transparent; color: #3194d0; cursor: pointer;" target="_blank">TCP、UDP、Socket、HTTP你不知道的故事</a><br><a href="https://www.jianshu.com/p/ed33413c1e3b" style="background-color: transparent; color: #3194d0; cursor: pointer;" target="_blank">UDP 的模样和你想的是否一样</a><br><a href="https://www.jianshu.com/p/b0082662b22e" style="background-color: transparent; color: #3194d0; cursor: pointer;" target="_blank">跟着动画学习 TCP 三次握手和四次挥手</a><br><a href="https://www.jianshu.com/p/742897d6b0f8" style="background-color: transparent; color: #3194d0; cursor: pointer;" target="_blank">TCP、UDP以及TCP滑窗，它们的区别</a></p>
</div>
              
              <br/><br/>
              <span style="color:red;">
                <a href="https://www.iteye.com/blog/java8988-2429662#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
              </span>
              <br/><br/><br/>
<span style="color:#E28822;">ITeye推荐</span>
<br/>
<ul><li><a href='/clicks/433' target='_blank'><span style="color:red;font-weight:bold;">—软件人才免语言低担保 赴美带薪读研！— </span></a></li></ul>
<br/><br/><br/>
              ]]>
            </description>
            <pubDate>Wed, 29 Aug 2018 16:30:27 +0800</pubDate>
            <link>https://www.iteye.com/blog/user/java8988/blog/2429662</link>
            <guid isPermaLink="false">https://www.iteye.com/blog/user/java8988/blog/2429662</guid>
          </item>
                  <item>
            <title>面试常问之长连接与短连接</title>
            <description>
              <![CDATA[
              <div class="iteye-blog-content-contain" style="font-size: 14px;">
<p>原文地址：<a href="https://www.jianshu.com/p/173009ccfd7b" title="原文链接" target="_blank">https://www.jianshu.com/p/173009ccfd7b</a> 转载请注明出处</p>
<p> </p>
<h1>短连接</h1>
<p>连接-&gt;传输数据-&gt;关闭连接</p>
<p>HTTP是无状态的，浏览器和服务器每进行一次HTTP操作，就建立一次连接，但任务结束就中断连接。</p>
<p>也可以这样说：短连接是指SOCKET连接后发送后接收完数据后马上断开连接。</p>
<h1>长连接</h1>
<p>连接-&gt;传输数据-&gt;保持连接 -&gt; 传输数据-&gt; ... -&gt;关闭连接。</p>
<p>长连接指建立SOCKET连接后不管是否使用都保持连接，但安全性较差。</p>
<h2>http的长连接</h2>
<p>HTTP也可以建立长连接的，使用Connection:keep-alive，HTTP 1.1默认进行持久连接。</p>
<p>HTTP1.1和HTTP1.0相比较而言，最大的区别就是增加了持久连接支持(貌似最新的 http1.0 可以显示的指定 keep-alive),但还是无状态的，或者说是不可以信任的。</p>
<p>什么时候用长连接，短连接？</p>
<p>长连接多用于操作频繁，点对点的通讯，而且连接数不能太多情况。</p>
<p>每个TCP连接都需要三步握手，这需要时间，如果每个操作都是先连接，再操作的话那么处理速度会降低很多，所以每个操作完后都不断开，每次处理时直接发送数据包就OK了，不用建立TCP连接。例如：数据库的连接用长连接， 如果用短连接频繁的通信会造成socket错误，而且频繁的socket 创建也是对资源的浪费。</p>
<p>而像WEB网站的http服务一般都用短链接，因为长连接对于服务端来说会耗费一定的资源，而像WEB网站这么频繁的成千上万甚至上亿客户端的连接用短连接会更省一些资源，如果用长连接，而且同时有成千上万的用户，如果每个用户都占用一个连接的话，那可想而知吧。</p>
<p>所以并发量大，但每个用户无需频繁操作情况下需用短连接好。</p>
<h1>补充与扩展</h1>
<p>通俗点讲，短连接就是一次TCP请求得到结果后,连接马上结束.而长连接并不马上断开,而一直保持着,直到长连接TIMEOUT(具体程序都有相关参数说明).长连接可以避免不断的进行TCP三次握手和四次挥手.</p>
<p>长连接(keepalive)是需要靠双方不断的发送探测包来维持的,keepalive期间服务端和客户端的TCP连接状态是ESTABLISHED。</p>
</div>
              
              <br/><br/>
              <span style="color:red;">
                <a href="https://www.iteye.com/blog/java8988-2429661#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
              </span>
              <br/><br/><br/>
<span style="color:#E28822;">ITeye推荐</span>
<br/>
<ul><li><a href='/clicks/433' target='_blank'><span style="color:red;font-weight:bold;">—软件人才免语言低担保 赴美带薪读研！— </span></a></li></ul>
<br/><br/><br/>
              ]]>
            </description>
            <pubDate>Wed, 29 Aug 2018 16:28:11 +0800</pubDate>
            <link>https://www.iteye.com/blog/user/java8988/blog/2429661</link>
            <guid isPermaLink="false">https://www.iteye.com/blog/user/java8988/blog/2429661</guid>
          </item>
                  <item>
            <title>HashMap详解</title>
            <description>
              <![CDATA[
              <div class="iteye-blog-content-contain" style="font-size: 14px;">
<h1>简介</h1>
<p>Java为数据结构中的映射定义了一个接口java.util.Map，此接口主要有四个常用的实现类，分别是HashMap、Hashtable、LinkedHashMap和TreeMap，类继承关系如下图所示：</p>
<p> </p>
<div class="image-package">
<div class="image-container" style="background-color: transparent; margin: 0px auto; max-width: 700px;">
<div class="image-container-fill"> </div>
<div class="image-view" style="width: 700px; height: 425.031px; overflow: hidden;"><img alt="" src="https://upload-images.jianshu.io/upload_images/11336294-bf008a9560e8c53b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/700"></div>
</div>
<div class="image-caption" style="min-width: 20%; max-width: 80%; display: inline-block; padding: 10px; margin: 0px auto; border-bottom: 1px solid #d9d9d9; font-size: 14px; color: #969696; line-height: 1.7;">image.png</div>
</div>
<p>下面针对各个实现类的特点做一些说明：</p>
<ol>
<li style="line-height: 30px;">
<p style="margin-bottom: 25px; overflow: visible;">HashMap:根据键的hashCode值存储数据，直接定位到它的值，因而具有很快的访问速度，但遍历顺序却是不确定的。 HashMap最多只允许一条记录的键为null，允许多条记录的值为null。HashMap非线程安全，即任一时刻可以有多个线程同时写HashMap，可能会导致数据的不一致。如果需要满足线程安全，可以用 Collections的synchronizedMap方法使HashMap具有线程安全的能力，或者使用ConcurrentHashMap。</p>
</li>
<li style="line-height: 30px;">
<p style="margin-bottom: 25px; overflow: visible;">HashTable:遗留类，很多映射的常用功能与HashMap类似，不同的是它承自Dictionary类，并且是线程安全的，任一时间只有一个线程能写Hashtable，并发性不如ConcurrentHashMap，因为ConcurrentHashMap引入了分段锁。Hashtable不建议在新代码中使用，不需要线程安全的场合可以用HashMap替换，需要线程安全的场合可以用ConcurrentHashMap替换。</p>
</li>
<li style="line-height: 30px;">
<p style="margin-bottom: 25px; overflow: visible;">LinkedHashMap:HashMap的一个子类，保存了记录的插入顺序，在用Iterator遍历LinkedHashMap时，先得到的记录肯定是先插入的，也可以在构造时带参数，按照访问次序排序。</p>
</li>
<li style="line-height: 30px;">
<p style="margin-bottom: 25px; overflow: visible;">TreeMap:实现SortedMap接口，能够把它保存的记录根据键排序，默认是按键值的升序排序，也可以指定排序的比较器，当用Iterator遍历TreeMap时，得到的记录是排过序的。如果使用排序的映射，建议使用TreeMap。在使用TreeMap时，key必须实现Comparable接口或者在构造TreeMap传入自定义的Comparator，否则会在运行时抛出java.lang.ClassCastException类型的异常。</p>
<blockquote style="padding: 20px; margin: 0px 0px 25px; border-left-width: 6px; border-left-color: #b4b4b4; background-color: #f7f7f7; line-height: 30px;">
<p style="overflow: visible; line-height: 1.7;">注意：对于上述四种Map类型的类，要求映射中的key是不可变对象。不可变对象是该对象在创建后它的哈希值不会被改变。如果对象的哈希值发生变化，Map对象很可能就定位不到映射的位置了。</p>
</blockquote>
</li>
</ol>
<table>
<tr>
名称
产生时间
是否有序
是否允许为空
数据结构
安全性
 
</tr>

<tr>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">HashMap</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">jdk1.2</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">无序</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">一条记录的key为空，允许多条记录的value为空</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">Jdk1.8之前 数组+链表；jdk1.8 数组+链表+红黑树</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">线程不安全</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;"> </td>
</tr>
<tr>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">HashTable</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">jdk1.1</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">无序</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">key、value都不允许为null</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">哈希表</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">线程安全</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;"> </td>
</tr>
<tr>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">LinkedHashMap</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">jdk1.4</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">有序，保存插入的顺序</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">允许为空</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">散列表和双向链表</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">线程不安全</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;"> </td>
</tr>
<tr>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">TreeMap</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">jdk1.2</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">有序，按照key排序</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">不允许出现重复的key</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">红黑树</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">线程不安全</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;"> </td>
</tr>

</table>
<p>通过上面的比较，我们知道了HashMap是Java的Map家族中一个普通成员，鉴于它可以满足大多数场景的使用条件，所以是使用频度最高的一个。下文我们主要结合源码，从存储结构、常用方法分析、扩容以及安全性等方面深入讲解HashMap的工作原理。</p>
<h1>内部实现</h1>
<p>搞清楚HashMap，首先需要知道HashMap是什么，即它的存储结构-字段；其次弄明白它能干什么，即它的功能实现-方法。下面我们针对这两个方面详细展开讲解。</p>
<h2>存储结构-字段</h2>
<p>从结构实现来讲，HashMap是数组+链表+红黑树（JDK1.8增加了红黑树部分）实现的，如下如所示。</p>
<div class="image-package">
<div class="image-container" style="background-color: transparent; margin: 0px auto; max-width: 700px;">
<div class="image-container-fill"> </div>
<div class="image-view" style="width: 700px; height: 529px; overflow: hidden;"><img alt="" src="https://upload-images.jianshu.io/upload_images/11336294-f14508e4413b0050.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/700"></div>
</div>
<div class="image-caption" style="min-width: 20%; max-width: 80%; display: inline-block; padding: 10px; margin: 0px auto; border-bottom: 1px solid #d9d9d9; font-size: 14px; color: #969696; line-height: 1.7;">image</div>
</div>
<ol>
<li style="line-height: 30px;">
<p style="margin-bottom: 25px; overflow: visible;">数据底层存储的是Node节点，Node是HashMap的一个内部类，实现了Map.Entry接口，本质是就是一个映射(键值对)。上图中的每个黑色圆点就是一个Node对象。</p>
</li>
<li style="line-height: 30px;">
<p style="margin-bottom: 25px; overflow: visible;">存储方式的优点：HashMap就是使用哈希表来存储的。哈希表为解决冲突，可以采用开放地址法和链地址法等来解决问题，Java中HashMap采用了链地址法。链地址法，简单来说，就是数组加链表的结合。在每个数组元素上都一个链表结构，当数据被Hash后，得到数组下标，把数据放在对应下标元素的链表上。</p>
</li>
</ol>
<pre class="hljs java"><code class="java" style="font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 12px; color: inherit; background-color: transparent; border-radius: 0px; padding: 0px; border: none; vertical-align: middle;"><span class="hljs-keyword" style="color: #c678dd;">static</span> <span class="hljs-keyword" style="color: #c678dd;">final</span> <span class="hljs-keyword" style="color: #c678dd;">float</span> DEFAULT_LOAD_FACTOR = <span class="hljs-number" style="color: #d19a66;">0.75f</span>; <span class="hljs-comment" style="color: #5c6370; font-style: italic;">// 负载因子</span>
<span class="hljs-keyword" style="color: #c678dd;">static</span> <span class="hljs-keyword" style="color: #c678dd;">final</span> <span class="hljs-keyword" style="color: #c678dd;">int</span> TREEIFY_THRESHOLD = <span class="hljs-number" style="color: #d19a66;">8</span>; <span class="hljs-comment" style="color: #5c6370; font-style: italic;">// 所能容纳的最大数据量的Node(键值对)个数</span>
<span class="hljs-keyword" style="color: #c678dd;">static</span> <span class="hljs-keyword" style="color: #c678dd;">final</span> <span class="hljs-keyword" style="color: #c678dd;">int</span> DEFAULT_INITIAL_CAPACITY = <span class="hljs-number" style="color: #d19a66;">1</span> &lt;&lt; <span class="hljs-number" style="color: #d19a66;">4</span>; <span class="hljs-comment" style="color: #5c6370; font-style: italic;">// aka 16 HashMap默认容量 16</span>
</code></pre>
<blockquote>
<p style="line-height: 1.7;">在JDK1.8版本中，对数据结构做了进一步的优化，引入了红黑树。而当链表长度太长（默认超过8）时，链表就转换为红黑树，利用红黑树快速增删改查的特点提高HashMap的性能</p>
</blockquote>
<h2>功能实现</h2>
<p>HashMap的内部功能实现很多，本文主要从根据key获取哈希桶数组索引位置、put方法的详细执行、扩容过程三个具有代表性的点深入展开讲解。</p>
<h3>1. 确定哈希桶数组索引位置</h3>
<p>不管增加、删除、查找键值对，定位到哈希桶数组的位置都是很关键的第一步。前面说过HashMap的数据结构是数组和链表的结合，所以我们当然希望这个HashMap里面的元素位置尽量分布均匀些，尽量使得每个位置上的元素数量只有一个，那么当我们用hash算法求得这个位置的时候，马上就可以知道对应位置的元素就是我们要的，不用遍历链表，大大优化了查询的效率。HashMap定位数组索引位置，直接决定了hash方法的离散性能。先看看源码的实现(方法一+方法二):</p>
<pre class="hljs java"><code class="java" style="font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 12px; color: inherit; background-color: transparent; border-radius: 0px; padding: 0px; border: none; vertical-align: middle;">方法一：
<span class="hljs-function"><span class="hljs-keyword" style="color: #c678dd;">static</span> <span class="hljs-keyword" style="color: #c678dd;">final</span> <span class="hljs-keyword" style="color: #c678dd;">int</span> <span class="hljs-title" style="color: #61aeee;">hash</span><span class="hljs-params">(Object key)</span> </span>{   <span class="hljs-comment" style="color: #5c6370; font-style: italic;">//jdk1.8 &amp; jdk1.7</span>
 <span class="hljs-keyword" style="color: #c678dd;">int</span> h;
 <span class="hljs-comment" style="color: #5c6370; font-style: italic;">// h = key.hashCode() 为第一步 取hashCode值</span>
 <span class="hljs-comment" style="color: #5c6370; font-style: italic;">// h ^ (h &gt;&gt;&gt; 16)  为第二步 高位参与运算</span>
 <span class="hljs-keyword" style="color: #c678dd;">return</span> (key == <span class="hljs-keyword" style="color: #c678dd;">null</span>) ? <span class="hljs-number" style="color: #d19a66;">0</span> : (h = key.hashCode()) ^ (h &gt;&gt;&gt; <span class="hljs-number" style="color: #d19a66;">16</span>);
}
方法二：
<span class="hljs-function"><span class="hljs-keyword" style="color: #c678dd;">static</span> <span class="hljs-keyword" style="color: #c678dd;">int</span> <span class="hljs-title" style="color: #61aeee;">indexFor</span><span class="hljs-params">(<span class="hljs-keyword" style="color: #c678dd;">int</span> h, <span class="hljs-keyword" style="color: #c678dd;">int</span> length)</span> </span>{  <span class="hljs-comment" style="color: #5c6370; font-style: italic;">//jdk1.7的源码，jdk1.8没有这个方法，但是实现原理一样的</span>
 <span class="hljs-keyword" style="color: #c678dd;">return</span> h &amp; (length-<span class="hljs-number" style="color: #d19a66;">1</span>);  <span class="hljs-comment" style="color: #5c6370; font-style: italic;">//第三步 取模运算</span>
}
</code></pre>
<p>这里的Hash算法本质上就是三步：<span style="font-weight: bold;">取key的hashCode值、高位运算、取模运算</span>。</p>
<p>对于任意给定的对象，只要它的hashCode()返回值相同，那么程序调用方法一所计算得到的Hash码值总是相同的。我们首先想到的就是把hash值对数组长度取模运算，这样一来，元素的分布相对来说是比较均匀的。但是，模运算的消耗还是比较大的，在HashMap中是这样做的：调用方法二来计算该对象应该保存在table数组的哪个索引处。</p>
<p>这个方法非常巧妙，它通过h &amp; (table.length -1)来得到该对象的保存位，而HashMap底层数组的长度总是2的n次方，这是HashMap在速度上的优化。当length总是2的n次方时，h&amp; (length-1)运算等价于对length取模，也就是h%length，但是&amp;比%具有更高的效率。</p>
<p>在JDK1.8的实现中，优化了高位运算的算法，通过hashCode()的高16位异或低16位实现的：(h = k.hashCode()) ^ (h &gt;&gt;&gt; 16)，主要是从速度、功效、质量来考虑的，这么做可以在数组table的length比较小的时候，也能保证考虑到高低Bit都参与到Hash的计算中，同时不会有太大的开销。</p>
<p>下面举例说明下，n为table的长度。</p>
<div class="image-package">
<div class="image-container" style="background-color: transparent; margin: 0px auto; max-width: 700px;">
<div class="image-container-fill"> </div>
<div class="image-view" style="width: 700px; height: 399.688px; overflow: hidden;"><img alt="" src="https://upload-images.jianshu.io/upload_images/11336294-3408319ce47527f2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/700"></div>
</div>
<div class="image-caption" style="min-width: 20%; max-width: 80%; display: inline-block; padding: 10px; margin: 0px auto; border-bottom: 1px solid #d9d9d9; font-size: 14px; color: #969696; line-height: 1.7;">image</div>
</div>
<h3>2. 分析HashMap的put方法</h3>
<p>HashMap的put方法执行过程可以通过下图来理解，自己有兴趣可以去对比源码更清楚地研究学习。</p>
<div class="image-package">
<div class="image-container" style="background-color: transparent; margin: 0px auto; max-width: 700px;">
<div class="image-container-fill"> </div>
<div class="image-view" style="width: 700px; height: 554px; overflow: hidden;"><img alt="" src="https://upload-images.jianshu.io/upload_images/11336294-51d866d4d14d0c4e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/700"></div>
</div>
<div class="image-caption" style="min-width: 20%; max-width: 80%; display: inline-block; padding: 10px; margin: 0px auto; border-bottom: 1px solid #d9d9d9; font-size: 14px; color: #969696; line-height: 1.7;">image</div>
</div>
<p>JDK1.8HashMap的put方法源码如下:</p>
<pre class="hljs java"><code class="java" style="font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 12px; color: inherit; background-color: transparent; border-radius: 0px; padding: 0px; border: none; vertical-align: middle;"><span class="hljs-number" style="color: #d19a66;">1</span> <span class="hljs-function"><span class="hljs-keyword" style="color: #c678dd;">public</span> V <span class="hljs-title" style="color: #61aeee;">put</span><span class="hljs-params">(K key, V value)</span> </span>{
 <span class="hljs-number" style="color: #d19a66;">2</span>     <span class="hljs-comment" style="color: #5c6370; font-style: italic;">// 对key的hashCode()做hash</span>
 <span class="hljs-number" style="color: #d19a66;">3</span>     <span class="hljs-keyword" style="color: #c678dd;">return</span> putVal(hash(key), key, value, <span class="hljs-keyword" style="color: #c678dd;">false</span>, <span class="hljs-keyword" style="color: #c678dd;">true</span>);
 <span class="hljs-number" style="color: #d19a66;">4</span> }
 <span class="hljs-number" style="color: #d19a66;">5</span> 
 <span class="hljs-number" style="color: #d19a66;">6</span> <span class="hljs-function"><span class="hljs-keyword" style="color: #c678dd;">final</span> V <span class="hljs-title" style="color: #61aeee;">putVal</span><span class="hljs-params">(<span class="hljs-keyword" style="color: #c678dd;">int</span> hash, K key, V value, <span class="hljs-keyword" style="color: #c678dd;">boolean</span> onlyIfAbsent,
 <span class="hljs-number" style="color: #d19a66;">7</span>                <span class="hljs-keyword" style="color: #c678dd;">boolean</span> evict)</span> </span>{
 <span class="hljs-number" style="color: #d19a66;">8</span>     Node&lt;K,V&gt;[] tab; Node&lt;K,V&gt; p; <span class="hljs-keyword" style="color: #c678dd;">int</span> n, i;
 <span class="hljs-number" style="color: #d19a66;">9</span>     <span class="hljs-comment" style="color: #5c6370; font-style: italic;">// 步骤①：tab为空则创建</span>
<span class="hljs-number" style="color: #d19a66;">10</span>     <span class="hljs-keyword" style="color: #c678dd;">if</span> ((tab = table) == <span class="hljs-keyword" style="color: #c678dd;">null</span> || (n = tab.length) == <span class="hljs-number" style="color: #d19a66;">0</span>)
<span class="hljs-number" style="color: #d19a66;">11</span>         n = (tab = resize()).length;
<span class="hljs-number" style="color: #d19a66;">12</span>     <span class="hljs-comment" style="color: #5c6370; font-style: italic;">// 步骤②：计算index，并对null做处理 </span>
<span class="hljs-number" style="color: #d19a66;">13</span>     <span class="hljs-keyword" style="color: #c678dd;">if</span> ((p = tab[i = (n - <span class="hljs-number" style="color: #d19a66;">1</span>) &amp; hash]) == <span class="hljs-keyword" style="color: #c678dd;">null</span>) 
<span class="hljs-number" style="color: #d19a66;">14</span>         tab[i] = newNode(hash, key, value, <span class="hljs-keyword" style="color: #c678dd;">null</span>);
<span class="hljs-number" style="color: #d19a66;">15</span>     <span class="hljs-keyword" style="color: #c678dd;">else</span> {
<span class="hljs-number" style="color: #d19a66;">16</span>         Node&lt;K,V&gt; e; K k;
<span class="hljs-number" style="color: #d19a66;">17</span>         <span class="hljs-comment" style="color: #5c6370; font-style: italic;">// 步骤③：节点key存在，直接覆盖value</span>
<span class="hljs-number" style="color: #d19a66;">18</span>         <span class="hljs-keyword" style="color: #c678dd;">if</span> (p.hash == hash &amp;&amp;
<span class="hljs-number" style="color: #d19a66;">19</span>             ((k = p.key) == key || (key != <span class="hljs-keyword" style="color: #c678dd;">null</span> &amp;&amp; key.equals(k))))
<span class="hljs-number" style="color: #d19a66;">20</span>             e = p;
<span class="hljs-number" style="color: #d19a66;">21</span>         <span class="hljs-comment" style="color: #5c6370; font-style: italic;">// 步骤④：判断该链为红黑树</span>
<span class="hljs-number" style="color: #d19a66;">22</span>         <span class="hljs-keyword" style="color: #c678dd;">else</span> <span class="hljs-keyword" style="color: #c678dd;">if</span> (p <span class="hljs-keyword" style="color: #c678dd;">instanceof</span> TreeNode)
<span class="hljs-number" style="color: #d19a66;">23</span>             e = ((TreeNode&lt;K,V&gt;)p).putTreeVal(<span class="hljs-keyword" style="color: #c678dd;">this</span>, tab, hash, key, value);
<span class="hljs-number" style="color: #d19a66;">24</span>         <span class="hljs-comment" style="color: #5c6370; font-style: italic;">// 步骤⑤：该链为链表</span>
<span class="hljs-number" style="color: #d19a66;">25</span>         <span class="hljs-keyword" style="color: #c678dd;">else</span> {
<span class="hljs-number" style="color: #d19a66;">26</span>             <span class="hljs-keyword" style="color: #c678dd;">for</span> (<span class="hljs-keyword" style="color: #c678dd;">int</span> binCount = <span class="hljs-number" style="color: #d19a66;">0</span>; ; ++binCount) {
<span class="hljs-number" style="color: #d19a66;">27</span>                 <span class="hljs-keyword" style="color: #c678dd;">if</span> ((e = p.next) == <span class="hljs-keyword" style="color: #c678dd;">null</span>) {
<span class="hljs-number" style="color: #d19a66;">28</span>                     p.next = newNode(hash, key,value,<span class="hljs-keyword" style="color: #c678dd;">null</span>);
 <span class="hljs-comment" style="color: #5c6370; font-style: italic;">//链表长度大于8转换为红黑树进行处理</span>
<span class="hljs-number" style="color: #d19a66;">29</span>                     <span class="hljs-keyword" style="color: #c678dd;">if</span> (binCount &gt;= TREEIFY_THRESHOLD - <span class="hljs-number" style="color: #d19a66;">1</span>) <span class="hljs-comment" style="color: #5c6370; font-style: italic;">// -1 for 1st  </span>
<span class="hljs-number" style="color: #d19a66;">30</span>                         treeifyBin(tab, hash);
<span class="hljs-number" style="color: #d19a66;">31</span>                     <span class="hljs-keyword" style="color: #c678dd;">break</span>;
<span class="hljs-number" style="color: #d19a66;">32</span>                 }
 <span class="hljs-comment" style="color: #5c6370; font-style: italic;">// key已经存在直接覆盖value</span>
<span class="hljs-number" style="color: #d19a66;">33</span>                 <span class="hljs-keyword" style="color: #c678dd;">if</span> (e.hash == hash &amp;&amp;
<span class="hljs-number" style="color: #d19a66;">34</span>                     ((k = e.key) == key || (key != <span class="hljs-keyword" style="color: #c678dd;">null</span> &amp;&amp; key.equals(k)))) 
<span class="hljs-number" style="color: #d19a66;">35</span>                            <span class="hljs-keyword" style="color: #c678dd;">break</span>;
<span class="hljs-number" style="color: #d19a66;">36</span>                 p = e;
<span class="hljs-number" style="color: #d19a66;">37</span>             }
<span class="hljs-number" style="color: #d19a66;">38</span>         }
<span class="hljs-number" style="color: #d19a66;">39</span> 
<span class="hljs-number" style="color: #d19a66;">40</span>         <span class="hljs-keyword" style="color: #c678dd;">if</span> (e != <span class="hljs-keyword" style="color: #c678dd;">null</span>) { <span class="hljs-comment" style="color: #5c6370; font-style: italic;">// existing mapping for key</span>
<span class="hljs-number" style="color: #d19a66;">41</span>             V oldValue = e.value;
<span class="hljs-number" style="color: #d19a66;">42</span>             <span class="hljs-keyword" style="color: #c678dd;">if</span> (!onlyIfAbsent || oldValue == <span class="hljs-keyword" style="color: #c678dd;">null</span>)
<span class="hljs-number" style="color: #d19a66;">43</span>                 e.value = value;
<span class="hljs-number" style="color: #d19a66;">44</span>             afterNodeAccess(e);
<span class="hljs-number" style="color: #d19a66;">45</span>             <span class="hljs-keyword" style="color: #c678dd;">return</span> oldValue;
<span class="hljs-number" style="color: #d19a66;">46</span>         }
<span class="hljs-number" style="color: #d19a66;">47</span>     }
​
<span class="hljs-number" style="color: #d19a66;">48</span>     ++modCount;
<span class="hljs-number" style="color: #d19a66;">49</span>     <span class="hljs-comment" style="color: #5c6370; font-style: italic;">// 步骤⑥：超过最大容量 就扩容</span>
<span class="hljs-number" style="color: #d19a66;">50</span>     <span class="hljs-keyword" style="color: #c678dd;">if</span> (++size &gt; threshold)
<span class="hljs-number" style="color: #d19a66;">51</span>         resize();
<span class="hljs-number" style="color: #d19a66;">52</span>     afterNodeInsertion(evict);
<span class="hljs-number" style="color: #d19a66;">53</span>     <span class="hljs-keyword" style="color: #c678dd;">return</span> <span class="hljs-keyword" style="color: #c678dd;">null</span>;
<span class="hljs-number" style="color: #d19a66;">54</span> }
</code></pre>
<p>①.判断键值对数组table[i]是否为空或为null，否则执行resize()进行扩容；</p>
<p>②.根据键值key计算hash值得到插入的数组索引i，如果table[i]==null，直接新建节点添加，转向⑥，如果table[i]不为空，转向③；</p>
<p>③.判断table[i]的首个元素是否和key一样，如果相同直接覆盖value，否则转向④，这里的相同指的是hashCode以及equals；</p>
<p>④.判断table[i] 是否为treeNode，即table[i] 是否是红黑树，如果是红黑树，则直接在树中插入键值对，否则转向⑤；</p>
<p>⑤.遍历table[i]，判断链表长度是否大于8，大于8的话把链表转换为红黑树，在红黑树中执行插入操作，否则进行链表的插入操作；遍历过程中若发现key已经存在直接覆盖value即可；</p>
<p>⑥.插入成功后，判断实际存在的键值对数量size是否超多了最大容量threshold，如果超过，进行扩容。</p>
<h3>3. 扩容机制</h3>
<p>扩容(resize)就是重新计算容量，向HashMap对象里不停的添加元素，而HashMap对象内部的数组无法装载更多的元素时，对象就需要扩大数组的长度，以便能装入更多的元素。当然Java里的数组是无法自动扩容的，方法是使用一个新的数组代替已有的容量小的数组，就像我们用一个小桶装水，如果想装更多的水，就得换大水桶。</p>
<p>我们分析下resize的源码，鉴于JDK1.8融入了红黑树，较复杂，为了便于理解我们仍然使用JDK1.7的代码，好理解一些，本质上区别不大，具体区别后文再说。</p>
<pre class="hljs java"><code class="java" style="font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 12px; color: inherit; background-color: transparent; border-radius: 0px; padding: 0px; border: none; vertical-align: middle;"><span class="hljs-number" style="color: #d19a66;">1</span> <span class="hljs-function"><span class="hljs-keyword" style="color: #c678dd;">void</span> <span class="hljs-title" style="color: #61aeee;">resize</span><span class="hljs-params">(<span class="hljs-keyword" style="color: #c678dd;">int</span> newCapacity)</span> </span>{   <span class="hljs-comment" style="color: #5c6370; font-style: italic;">//传入新的容量</span>
 <span class="hljs-number" style="color: #d19a66;">2</span>     Entry[] oldTable = table;    <span class="hljs-comment" style="color: #5c6370; font-style: italic;">//引用扩容前的Entry数组</span>
 <span class="hljs-number" style="color: #d19a66;">3</span>     <span class="hljs-keyword" style="color: #c678dd;">int</span> oldCapacity = oldTable.length; 
 <span class="hljs-number" style="color: #d19a66;">4</span>     <span class="hljs-keyword" style="color: #c678dd;">if</span> (oldCapacity == MAXIMUM_CAPACITY) {  <span class="hljs-comment" style="color: #5c6370; font-style: italic;">//扩容前的数组大小如果已经达到最大(2^30)了</span>
 <span class="hljs-number" style="color: #d19a66;">5</span>         threshold = Integer.MAX_VALUE; <span class="hljs-comment" style="color: #5c6370; font-style: italic;">//修改阈值为int的最大值(2^31-1)，这样以后就不会扩容了</span>
 <span class="hljs-number" style="color: #d19a66;">6</span>         <span class="hljs-keyword" style="color: #c678dd;">return</span>;
 <span class="hljs-number" style="color: #d19a66;">7</span>     }
 <span class="hljs-number" style="color: #d19a66;">8</span>
 <span class="hljs-number" style="color: #d19a66;">9</span>     Entry[] newTable = <span class="hljs-keyword" style="color: #c678dd;">new</span> Entry[newCapacity];  <span class="hljs-comment" style="color: #5c6370; font-style: italic;">//初始化一个新的Entry数组</span>
<span class="hljs-number" style="color: #d19a66;">10</span>     transfer(newTable);                         <span class="hljs-comment" style="color: #5c6370; font-style: italic;">//！！将数据转移到新的Entry数组里</span>
<span class="hljs-number" style="color: #d19a66;">11</span>     table = newTable;                           <span class="hljs-comment" style="color: #5c6370; font-style: italic;">//HashMap的table属性引用新的Entry数组</span>
<span class="hljs-number" style="color: #d19a66;">12</span>     threshold = (<span class="hljs-keyword" style="color: #c678dd;">int</span>)(newCapacity * loadFactor);<span class="hljs-comment" style="color: #5c6370; font-style: italic;">//修改阈值</span>
<span class="hljs-number" style="color: #d19a66;">13</span> }
</code></pre>
<p>这里就是使用一个容量更大的数组来代替已有的容量小的数组，transfer()方法将原有Entry数组的元素拷贝到新的Entry数组里。</p>
<pre class="hljs java"><code class="java" style="font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 12px; color: inherit; background-color: transparent; border-radius: 0px; padding: 0px; border: none; vertical-align: middle;"> <span class="hljs-number" style="color: #d19a66;">1</span> <span class="hljs-function"><span class="hljs-keyword" style="color: #c678dd;">void</span> <span class="hljs-title" style="color: #61aeee;">transfer</span><span class="hljs-params">(Entry[] newTable)</span> </span>{
 <span class="hljs-number" style="color: #d19a66;">2</span>     Entry[] src = table;                   <span class="hljs-comment" style="color: #5c6370; font-style: italic;">//src引用了旧的Entry数组</span>
 <span class="hljs-number" style="color: #d19a66;">3</span>     <span class="hljs-keyword" style="color: #c678dd;">int</span> newCapacity = newTable.length;
 <span class="hljs-number" style="color: #d19a66;">4</span>     <span class="hljs-keyword" style="color: #c678dd;">for</span> (<span class="hljs-keyword" style="color: #c678dd;">int</span> j = <span class="hljs-number" style="color: #d19a66;">0</span>; j &lt; src.length; j++) { <span class="hljs-comment" style="color: #5c6370; font-style: italic;">//遍历旧的Entry数组</span>
 <span class="hljs-number" style="color: #d19a66;">5</span>         Entry&lt;K,V&gt; e = src[j];             <span class="hljs-comment" style="color: #5c6370; font-style: italic;">//取得旧Entry数组的每个元素</span>
 <span class="hljs-number" style="color: #d19a66;">6</span>         <span class="hljs-keyword" style="color: #c678dd;">if</span> (e != <span class="hljs-keyword" style="color: #c678dd;">null</span>) {
 <span class="hljs-number" style="color: #d19a66;">7</span>             src[j] = <span class="hljs-keyword" style="color: #c678dd;">null</span>;<span class="hljs-comment" style="color: #5c6370; font-style: italic;">//释放旧Entry数组的对象引用（for循环后，旧的Entry数组不再引用任何对象）</span>
 <span class="hljs-number" style="color: #d19a66;">8</span>             <span class="hljs-keyword" style="color: #c678dd;">do</span> {
 <span class="hljs-number" style="color: #d19a66;">9</span>                 Entry&lt;K,V&gt; next = e.next;
<span class="hljs-number" style="color: #d19a66;">10</span>                 <span class="hljs-keyword" style="color: #c678dd;">int</span> i = indexFor(e.hash, newCapacity); <span class="hljs-comment" style="color: #5c6370; font-style: italic;">//！！重新计算每个元素在数组中的位置</span>
<span class="hljs-number" style="color: #d19a66;">11</span>                 e.next = newTable[i]; <span class="hljs-comment" style="color: #5c6370; font-style: italic;">//标记[1]</span>
<span class="hljs-number" style="color: #d19a66;">12</span>                 newTable[i] = e;      <span class="hljs-comment" style="color: #5c6370; font-style: italic;">//将元素放在数组上</span>
<span class="hljs-number" style="color: #d19a66;">13</span>                 e = next;             <span class="hljs-comment" style="color: #5c6370; font-style: italic;">//访问下一个Entry链上的元素</span>
<span class="hljs-number" style="color: #d19a66;">14</span>             } <span class="hljs-keyword" style="color: #c678dd;">while</span> (e != <span class="hljs-keyword" style="color: #c678dd;">null</span>);
<span class="hljs-number" style="color: #d19a66;">15</span>         }
<span class="hljs-number" style="color: #d19a66;">16</span>     }
<span class="hljs-number" style="color: #d19a66;">17</span> }
</code></pre>
<p>newTable[i]的引用赋给了e.next，也就是使用了单链表的头插入方式，同一位置上新元素总会被放在链表的头部位置；这样先放在一个索引上的元素终会被放到Entry链的尾部(如果发生了hash冲突的话），这一点和Jdk1.8有区别，下文详解。在旧数组中同一条Entry链上的元素，通过重新计算索引位置后，有可能被放到了新数组的不同位置上。</p>
<p>下面我们讲解下JDK1.8做了哪些优化。经过观测可以发现，我们使用的是2次幂的扩展(指长度扩为原来2倍)，所以，元素的位置要么是在原位置，要么是在原位置再移动2次幂的位置。看下图可以明白这句话的意思，n为table的长度，图（a）表示扩容前的key1和key2两种key确定索引位置的示例，图（b）表示扩容后key1和key2两种key确定索引位置的示例，其中hash1是key1对应的哈希与高位运算结果。</p>
<div class="image-package">
<div class="image-container" style="background-color: transparent; margin: 0px auto; max-width: 700px;">
<div class="image-container-fill"> </div>
<div class="image-view" style="width: 700px; height: 191.297px; overflow: hidden;"><img alt="" src="https://upload-images.jianshu.io/upload_images/11336294-df6727aedb754c8b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/700"></div>
</div>
<div class="image-caption" style="min-width: 20%; max-width: 80%; display: inline-block; padding: 10px; margin: 0px auto; border-bottom: 1px solid #d9d9d9; font-size: 14px; color: #969696; line-height: 1.7;">image</div>
</div>
<p>元素在重新计算hash之后，因为n变为2倍，那么n-1的mask范围在高位多1bit(红色)，因此新的index就会发生这样的变化：</p>
<div class="image-package">
<div class="image-container" style="background-color: transparent; margin: 0px auto; max-width: 700px;">
<div class="image-container-fill"> </div>
<div class="image-view" style="width: 700px; height: 132.859px; overflow: hidden;"><img alt="" src="https://upload-images.jianshu.io/upload_images/11336294-f4d909eec3ca3302.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/700"></div>
</div>
<div class="image-caption" style="min-width: 20%; max-width: 80%; display: inline-block; padding: 10px; margin: 0px auto; border-bottom: 1px solid #d9d9d9; font-size: 14px; color: #969696; line-height: 1.7;">image</div>
</div>
<p>因此，我们在扩充HashMap的时候，不需要像JDK1.7的实现那样重新计算hash，只需要看看原来的hash值新增的那个bit是1还是0就好了，是0的话索引没变，是1的话索引变成“原索引+oldCap”，可以看看下图为16扩充为32的resize示意图：</p>
<div class="image-package">
<div class="image-container" style="background-color: transparent; margin: 0px auto; max-width: 700px;">
<div class="image-container-fill"> </div>
<div class="image-view" style="width: 700px; height: 402px; overflow: hidden;"><img alt="" src="https://upload-images.jianshu.io/upload_images/11336294-ec167d38e3680f40.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/700"></div>
</div>
<div class="image-caption" style="min-width: 20%; max-width: 80%; display: inline-block; padding: 10px; margin: 0px auto; border-bottom: 1px solid #d9d9d9; font-size: 14px; color: #969696; line-height: 1.7;">image</div>
</div>
<p>这个设计确实非常的巧妙，既省去了重新计算hash值的时间，而且同时，由于新增的1bit是0还是1可以认为是随机的，因此resize的过程，均匀的把之前的冲突的节点分散到新的bucket了。这一块就是JDK1.8新增的优化点。有一点注意区别，JDK1.7中rehash的时候，旧链表迁移新链表的时候，如果在新表的数组索引位置相同，则链表元素会倒置，但是从上图可以看出，JDK1.8不会倒置。有兴趣的同学可以研究下JDK1.8的resize源码，写的很赞，如下:</p>
<pre class="hljs java"><code class="java" style="font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 12px; color: inherit; background-color: transparent; border-radius: 0px; padding: 0px; border: none; vertical-align: middle;"><span class="hljs-number" style="color: #d19a66;">1</span> <span class="hljs-keyword" style="color: #c678dd;">final</span> Node&lt;K,V&gt;[] resize() {
 <span class="hljs-number" style="color: #d19a66;">2</span>     Node&lt;K,V&gt;[] oldTab = table;
 <span class="hljs-number" style="color: #d19a66;">3</span>     <span class="hljs-keyword" style="color: #c678dd;">int</span> oldCap = (oldTab == <span class="hljs-keyword" style="color: #c678dd;">null</span>) ? <span class="hljs-number" style="color: #d19a66;">0</span> : oldTab.length;
 <span class="hljs-number" style="color: #d19a66;">4</span>     <span class="hljs-keyword" style="color: #c678dd;">int</span> oldThr = threshold;
 <span class="hljs-number" style="color: #d19a66;">5</span>     <span class="hljs-keyword" style="color: #c678dd;">int</span> newCap, newThr = <span class="hljs-number" style="color: #d19a66;">0</span>;
 <span class="hljs-number" style="color: #d19a66;">6</span>     <span class="hljs-keyword" style="color: #c678dd;">if</span> (oldCap &gt; <span class="hljs-number" style="color: #d19a66;">0</span>) {
 <span class="hljs-number" style="color: #d19a66;">7</span>         <span class="hljs-comment" style="color: #5c6370; font-style: italic;">// 超过最大值就不再扩充了，就只好随你碰撞去吧</span>
 <span class="hljs-number" style="color: #d19a66;">8</span>         <span class="hljs-keyword" style="color: #c678dd;">if</span> (oldCap &gt;= MAXIMUM_CAPACITY) {
 <span class="hljs-number" style="color: #d19a66;">9</span>             threshold = Integer.MAX_VALUE;
<span class="hljs-number" style="color: #d19a66;">10</span>             <span class="hljs-keyword" style="color: #c678dd;">return</span> oldTab;
<span class="hljs-number" style="color: #d19a66;">11</span>         }
<span class="hljs-number" style="color: #d19a66;">12</span>         <span class="hljs-comment" style="color: #5c6370; font-style: italic;">// 没超过最大值，就扩充为原来的2倍</span>
<span class="hljs-number" style="color: #d19a66;">13</span>         <span class="hljs-keyword" style="color: #c678dd;">else</span> <span class="hljs-keyword" style="color: #c678dd;">if</span> ((newCap = oldCap &lt;&lt; <span class="hljs-number" style="color: #d19a66;">1</span>) &lt; MAXIMUM_CAPACITY &amp;&amp;
<span class="hljs-number" style="color: #d19a66;">14</span>                  oldCap &gt;= DEFAULT_INITIAL_CAPACITY)
<span class="hljs-number" style="color: #d19a66;">15</span>             newThr = oldThr &lt;&lt; <span class="hljs-number" style="color: #d19a66;">1</span>; <span class="hljs-comment" style="color: #5c6370; font-style: italic;">// double threshold</span>
<span class="hljs-number" style="color: #d19a66;">16</span>     }
<span class="hljs-number" style="color: #d19a66;">17</span>     <span class="hljs-keyword" style="color: #c678dd;">else</span> <span class="hljs-keyword" style="color: #c678dd;">if</span> (oldThr &gt; <span class="hljs-number" style="color: #d19a66;">0</span>) <span class="hljs-comment" style="color: #5c6370; font-style: italic;">// initial capacity was placed in threshold</span>
<span class="hljs-number" style="color: #d19a66;">18</span>         newCap = oldThr;
<span class="hljs-number" style="color: #d19a66;">19</span>     <span class="hljs-keyword" style="color: #c678dd;">else</span> {               <span class="hljs-comment" style="color: #5c6370; font-style: italic;">// zero initial threshold signifies using defaults</span>
<span class="hljs-number" style="color: #d19a66;">20</span>         newCap = DEFAULT_INITIAL_CAPACITY;
<span class="hljs-number" style="color: #d19a66;">21</span>         newThr = (<span class="hljs-keyword" style="color: #c678dd;">int</span>)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
<span class="hljs-number" style="color: #d19a66;">22</span>     }
<span class="hljs-number" style="color: #d19a66;">23</span>     <span class="hljs-comment" style="color: #5c6370; font-style: italic;">// 计算新的resize上限</span>
<span class="hljs-number" style="color: #d19a66;">24</span>     <span class="hljs-keyword" style="color: #c678dd;">if</span> (newThr == <span class="hljs-number" style="color: #d19a66;">0</span>) {
<span class="hljs-number" style="color: #d19a66;">25</span> 
<span class="hljs-number" style="color: #d19a66;">26</span>         <span class="hljs-keyword" style="color: #c678dd;">float</span> ft = (<span class="hljs-keyword" style="color: #c678dd;">float</span>)newCap * loadFactor;
<span class="hljs-number" style="color: #d19a66;">27</span>         newThr = (newCap &lt; MAXIMUM_CAPACITY &amp;&amp; ft &lt; (<span class="hljs-keyword" style="color: #c678dd;">float</span>)MAXIMUM_CAPACITY ?
<span class="hljs-number" style="color: #d19a66;">28</span>                   (<span class="hljs-keyword" style="color: #c678dd;">int</span>)ft : Integer.MAX_VALUE);
<span class="hljs-number" style="color: #d19a66;">29</span>     }
<span class="hljs-number" style="color: #d19a66;">30</span>     threshold = newThr;
<span class="hljs-number" style="color: #d19a66;">31</span>     <span class="hljs-meta" style="color: #61aeee;">@SuppressWarnings</span>({<span class="hljs-string" style="color: #98c379;">"rawtypes"</span>，<span class="hljs-string" style="color: #98c379;">"unchecked"</span>})
<span class="hljs-number" style="color: #d19a66;">32</span>         Node&lt;K,V&gt;[] newTab = (Node&lt;K,V&gt;[])<span class="hljs-keyword" style="color: #c678dd;">new</span> Node[newCap];
<span class="hljs-number" style="color: #d19a66;">33</span>     table = newTab;
<span class="hljs-number" style="color: #d19a66;">34</span>     <span class="hljs-keyword" style="color: #c678dd;">if</span> (oldTab != <span class="hljs-keyword" style="color: #c678dd;">null</span>) {
<span class="hljs-number" style="color: #d19a66;">35</span>         <span class="hljs-comment" style="color: #5c6370; font-style: italic;">// 把每个bucket都移动到新的buckets中</span>
<span class="hljs-number" style="color: #d19a66;">36</span>         <span class="hljs-keyword" style="color: #c678dd;">for</span> (<span class="hljs-keyword" style="color: #c678dd;">int</span> j = <span class="hljs-number" style="color: #d19a66;">0</span>; j &lt; oldCap; ++j) {
<span class="hljs-number" style="color: #d19a66;">37</span>             Node&lt;K,V&gt; e;
<span class="hljs-number" style="color: #d19a66;">38</span>             <span class="hljs-keyword" style="color: #c678dd;">if</span> ((e = oldTab[j]) != <span class="hljs-keyword" style="color: #c678dd;">null</span>) {
<span class="hljs-number" style="color: #d19a66;">39</span>                 oldTab[j] = <span class="hljs-keyword" style="color: #c678dd;">null</span>;
<span class="hljs-number" style="color: #d19a66;">40</span>                 <span class="hljs-keyword" style="color: #c678dd;">if</span> (e.next == <span class="hljs-keyword" style="color: #c678dd;">null</span>)
<span class="hljs-number" style="color: #d19a66;">41</span>                     newTab[e.hash &amp; (newCap - <span class="hljs-number" style="color: #d19a66;">1</span>)] = e;
<span class="hljs-number" style="color: #d19a66;">42</span>                 <span class="hljs-keyword" style="color: #c678dd;">else</span> <span class="hljs-keyword" style="color: #c678dd;">if</span> (e <span class="hljs-keyword" style="color: #c678dd;">instanceof</span> TreeNode)
<span class="hljs-number" style="color: #d19a66;">43</span>                     ((TreeNode&lt;K,V&gt;)e).split(<span class="hljs-keyword" style="color: #c678dd;">this</span>, newTab, j, oldCap);
<span class="hljs-number" style="color: #d19a66;">44</span>                 <span class="hljs-keyword" style="color: #c678dd;">else</span> { <span class="hljs-comment" style="color: #5c6370; font-style: italic;">// 链表优化重hash的代码块</span>
<span class="hljs-number" style="color: #d19a66;">45</span>                     Node&lt;K,V&gt; loHead = <span class="hljs-keyword" style="color: #c678dd;">null</span>, loTail = <span class="hljs-keyword" style="color: #c678dd;">null</span>;
<span class="hljs-number" style="color: #d19a66;">46</span>                     Node&lt;K,V&gt; hiHead = <span class="hljs-keyword" style="color: #c678dd;">null</span>, hiTail = <span class="hljs-keyword" style="color: #c678dd;">null</span>;
<span class="hljs-number" style="color: #d19a66;">47</span>                     Node&lt;K,V&gt; next;
<span class="hljs-number" style="color: #d19a66;">48</span>                     <span class="hljs-keyword" style="color: #c678dd;">do</span> {
<span class="hljs-number" style="color: #d19a66;">49</span>                         next = e.next;
<span class="hljs-number" style="color: #d19a66;">50</span>                         <span class="hljs-comment" style="color: #5c6370; font-style: italic;">// 原索引</span>
<span class="hljs-number" style="color: #d19a66;">51</span>                         <span class="hljs-keyword" style="color: #c678dd;">if</span> ((e.hash &amp; oldCap) == <span class="hljs-number" style="color: #d19a66;">0</span>) {
<span class="hljs-number" style="color: #d19a66;">52</span>                             <span class="hljs-keyword" style="color: #c678dd;">if</span> (loTail == <span class="hljs-keyword" style="color: #c678dd;">null</span>)
<span class="hljs-number" style="color: #d19a66;">53</span>                                 loHead = e;
<span class="hljs-number" style="color: #d19a66;">54</span>                             <span class="hljs-keyword" style="color: #c678dd;">else</span>
<span class="hljs-number" style="color: #d19a66;">55</span>                                 loTail.next = e;
<span class="hljs-number" style="color: #d19a66;">56</span>                             loTail = e;
<span class="hljs-number" style="color: #d19a66;">57</span>                         }
<span class="hljs-number" style="color: #d19a66;">58</span>                         <span class="hljs-comment" style="color: #5c6370; font-style: italic;">// 原索引+oldCap</span>
<span class="hljs-number" style="color: #d19a66;">59</span>                         <span class="hljs-keyword" style="color: #c678dd;">else</span> {
<span class="hljs-number" style="color: #d19a66;">60</span>                             <span class="hljs-keyword" style="color: #c678dd;">if</span> (hiTail == <span class="hljs-keyword" style="color: #c678dd;">null</span>)
<span class="hljs-number" style="color: #d19a66;">61</span>                                 hiHead = e;
<span class="hljs-number" style="color: #d19a66;">62</span>                             <span class="hljs-keyword" style="color: #c678dd;">else</span>
<span class="hljs-number" style="color: #d19a66;">63</span>                                 hiTail.next = e;
<span class="hljs-number" style="color: #d19a66;">64</span>                             hiTail = e;
<span class="hljs-number" style="color: #d19a66;">65</span>                         }
<span class="hljs-number" style="color: #d19a66;">66</span>                     } <span class="hljs-keyword" style="color: #c678dd;">while</span> ((e = next) != <span class="hljs-keyword" style="color: #c678dd;">null</span>);
<span class="hljs-number" style="color: #d19a66;">67</span>                     <span class="hljs-comment" style="color: #5c6370; font-style: italic;">// 原索引放到bucket里</span>
<span class="hljs-number" style="color: #d19a66;">68</span>                     <span class="hljs-keyword" style="color: #c678dd;">if</span> (loTail != <span class="hljs-keyword" style="color: #c678dd;">null</span>) {
<span class="hljs-number" style="color: #d19a66;">69</span>                         loTail.next = <span class="hljs-keyword" style="color: #c678dd;">null</span>;
<span class="hljs-number" style="color: #d19a66;">70</span>                         newTab[j] = loHead;
<span class="hljs-number" style="color: #d19a66;">71</span>                     }
<span class="hljs-number" style="color: #d19a66;">72</span>                     <span class="hljs-comment" style="color: #5c6370; font-style: italic;">// 原索引+oldCap放到bucket里</span>
<span class="hljs-number" style="color: #d19a66;">73</span>                     <span class="hljs-keyword" style="color: #c678dd;">if</span> (hiTail != <span class="hljs-keyword" style="color: #c678dd;">null</span>) {
<span class="hljs-number" style="color: #d19a66;">74</span>                         hiTail.next = <span class="hljs-keyword" style="color: #c678dd;">null</span>;
<span class="hljs-number" style="color: #d19a66;">75</span>                         newTab[j + oldCap] = hiHead;
<span class="hljs-number" style="color: #d19a66;">76</span>                     }
<span class="hljs-number" style="color: #d19a66;">77</span>                 }
<span class="hljs-number" style="color: #d19a66;">78</span>             }
<span class="hljs-number" style="color: #d19a66;">79</span>         }
<span class="hljs-number" style="color: #d19a66;">80</span>     }
<span class="hljs-number" style="color: #d19a66;">81</span>     <span class="hljs-keyword" style="color: #c678dd;">return</span> newTab;
<span class="hljs-number" style="color: #d19a66;">82</span> }
</code></pre>
<h1>线程安全性</h1>
<p>线程不安全的，在多线程场景下，使用线程安全的ConcurrentHashMap</p>
<h1><span>小结</span></h1>
<p>(1) 扩容是一个特别耗性能的操作，所以当程序员在使用HashMap的时候，估算map的大小，初始化的时候给一个大致的数值，避免map进行频繁的扩容。</p>
<p>(2) 负载因子是可以修改的，也可以大于1，但是建议不要轻易修改，除非情况非常特殊。</p>
<p>(3) HashMap是线程不安全的，不要在并发的环境中同时操作HashMap，建议使用ConcurrentHashMap。</p>
<p>(4) JDK1.8引入红黑树大程度优化了HashMap的性能。</p>
<p><span style="font-weight: bold;">参考</span><br><a href="https://tech.meituan.com/java_hashmap.html" style="background-color: transparent; color: #3194d0; cursor: pointer;" target="_blank">Java 8系列之重新认识HashMap</a></p>
</div>
              
              <br/><br/>
              <span style="color:red;">
                <a href="https://www.iteye.com/blog/java8988-2428756#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
              </span>
              <br/><br/><br/>
<span style="color:#E28822;">ITeye推荐</span>
<br/>
<ul><li><a href='/clicks/433' target='_blank'><span style="color:red;font-weight:bold;">—软件人才免语言低担保 赴美带薪读研！— </span></a></li></ul>
<br/><br/><br/>
              ]]>
            </description>
            <pubDate>Wed, 15 Aug 2018 14:50:47 +0800</pubDate>
            <link>https://www.iteye.com/blog/user/java8988/blog/2428756</link>
            <guid isPermaLink="false">https://www.iteye.com/blog/user/java8988/blog/2428756</guid>
          </item>
                  <item>
            <title>JVM内存管理</title>
            <description>
              <![CDATA[
              <div class="iteye-blog-content-contain" style="font-size: 14px;">
<h3>栈</h3>
<p>一般是指 堆内存(Heap)的管理，因为栈(stack)、PC寄存器(PC Register)、本地方法栈(Native Method Stack)都是和线程一样的生命周期<br>-Xss 设置栈内存大小<br><span style="font-weight: bold;">栈是不需要垃圾回收的</span>，尽管说垃圾回收是java内存管理的一个很热的话题，栈中的对象如果用垃圾回收的观点来看，他永远是live状态，是可以reachable的，所以也不需要回收，他占有的空间随着Thread的结束而释放</p>
<h3>堆</h3>
<p>堆内存分为以下几个区：<br>Old Space 、 Eden 、From Space、To Space</p>
<div class="image-package">
<div class="image-container" style="background-color: transparent; margin: 0px auto; max-width: 548px;">
<div class="image-view" style="width: 548px; height: 278px; overflow: hidden;"><img alt="" src="https://upload-images.jianshu.io/upload_images/11336294-1be2f85b77c009eb.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/548"></div>
</div>
<div class="image-caption" style="min-width: 20%; max-width: 80%; display: inline-block; padding: 10px; margin: 0px auto; border-bottom: 1px solid #d9d9d9; font-size: 14px; color: #969696; line-height: 1.7;">图示</div>
</div>
<p> </p>
<p>-Xms和-Xmx来指定堆内存最小值和最大值<br>通过-Xmn来指定Young Generation的大小<br>通过-XX:NewRatio来指定Eden区的大小，在Xms和Xmx相等的情况下，该参数不需要设置<br>通过-XX：SurvivorRatio来设置Eden和一个Survivor区的比值</p>
<h2>垃圾回收</h2>
<h3>JVM中会在以下情况触发回收</h3>
<ol>
<li style="line-height: 30px;">
<p style="margin-bottom: 25px; overflow: visible;">对象没有被引用</p>
</li>
<li style="line-height: 30px;">
<p style="margin-bottom: 25px; overflow: visible;">作用域发生未捕捉异常</p>
</li>
<li style="line-height: 30px;">
<p style="margin-bottom: 25px; overflow: visible;">程序正常执行完毕</p>
</li>
<li style="line-height: 30px;">
<p style="margin-bottom: 25px; overflow: visible;">程序执行了System.exit()</p>
</li>
<li style="line-height: 30px;">
<p style="margin-bottom: 25px; overflow: visible;">程序发生意外终止</p>
</li>
</ol>
<h3>如何确定某个对象是垃圾</h3>
<p>1.引用计数法：对象配备一个整形计数器，引用一次+1，引用失效-1，计数器=0，表示对象不再被使用<br>2.可达性分析：GC Roots，如果一个对象不能达到GC Roots的时候，说明可以被回收</p>
<h3>垃圾回收算法</h3>
<p> </p>
<p> </p>
<p><span>1.标记清除法：标记阶段(标记出所有需要被回收的对象)，清除阶段(回收被标记的对象所占用的空间)</span></p>
<div class="image-package">
<div class="image-container" style="background-color: transparent; margin: 0px auto; max-width: 682px;">
<div class="image-view" style="width: 682px; height: 451px; overflow: hidden;"><img alt="" src="https://upload-images.jianshu.io/upload_images/11336294-ccff8f37b0416a88.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/682"></div>
</div>
<div class="image-caption" style="min-width: 20%; max-width: 80%; display: inline-block; padding: 10px; margin: 0px auto; border-bottom: 1px solid #d9d9d9; font-size: 14px; color: #969696; line-height: 1.7;">标记清除法</div>
</div>
<blockquote>
<p style="line-height: 1.7;">注意：标记清除算法先通过根节点标记所有可达对象，然后清除所有不可达对象，完成垃圾回收<br>缺点：效率低，内存碎片化严重(后续大对象找不到可利用的空间)</p>
</blockquote>
<p> </p>
<p> </p>
<p><span>2.复制算法：将内存容量分成两块，每次只使用其中一块，当这块内存用完的时候，将存活的对象复制到另外一块，然后再把已使用的内存空间一次性清理掉</span></p>
<div class="image-package">
<div class="image-container" style="background-color: transparent; margin: 0px auto; max-width: 700px;">
<div class="image-container-fill"> </div>
<div class="image-view" style="width: 700px; height: 411.172px; overflow: hidden;"><img alt="" src="https://upload-images.jianshu.io/upload_images/11336294-f906df07c6bf41ac.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/700"></div>
</div>
<div class="image-caption" style="min-width: 20%; max-width: 80%; display: inline-block; padding: 10px; margin: 0px auto; border-bottom: 1px solid #d9d9d9; font-size: 14px; color: #969696; line-height: 1.7;">复制算法</div>
</div>
<blockquote>
<p style="line-height: 1.7;">优点：算法实现简单，效率高，不易产生碎片<br>缺点：内存使用空间被压缩到一半</p>
</blockquote>
<p> </p>
<p> </p>
<p><span>3.标记整理法：与标记清除法一样，区别在与完成标记后，不是直接清理可回收对象，而是将存活对象都移向内存的一端，然后清理掉端边界以后的内存</span></p>
<div class="image-package">
<div class="image-container" style="background-color: transparent; margin: 0px auto; max-width: 679px;">
<div class="image-container-fill"> </div>
<div class="image-view" style="width: 679px; height: 446.984px; overflow: hidden;"><img alt="" src="https://upload-images.jianshu.io/upload_images/11336294-e18a6b882b6828b8.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/679"></div>
</div>
<div class="image-caption" style="min-width: 20%; max-width: 80%; display: inline-block; padding: 10px; margin: 0px auto; border-bottom: 1px solid #d9d9d9; font-size: 14px; color: #969696; line-height: 1.7;">标记整理法</div>
</div>
<blockquote>
<p style="line-height: 1.7;">注意：标记整理算法的最终效果等同于标记清除算法执行完成后，再进行一次内存碎片的整理，因此也叫标记清除压缩算法</p>
</blockquote>
<p>4.分代收集法：<br>核心思想：根据对象的存活生命周期将内存划分为若干不同的区域<br>新生代：每次垃圾回收时都有大量对象被回收<br>老年代：每次垃圾回收时只有少量对象需要被回收<br>新生代一般采用复制算法<br>老年代采用标记整理算法</p>
<blockquote>
<p style="line-height: 1.7;">注意：在堆之外还有一个永久代(Permanent Generation)，它用来存储class类，方法，常量描述等。对永久代的回收主要包括废弃常量和无用的类</p>
</blockquote>
<h3>垃圾收集器</h3>
<p><span style="font-weight: bold;">新生代垃圾收集器有Serial、ParNew、Parallel Scavenge，G1，属于老年代的垃圾收集器有CMS、Serial Old、Parallel Old和G1.</span>其中的G1是一种既可以对新生代对象也可以对老年代对象进行回收的垃圾收集器。</p>
<p><span style="font-weight: bold;">Serial</span> 单线程垃圾收集器，针对新生代的收集器，采用复制算法</p>
<p><span style="font-weight: bold;">ParNew</span> Serial收集器的多线程版本，采用复制算法，伴随着CPU数量的增加，收集效率也会大大增加</p>
<p><span style="font-weight: bold;">Parallel Scavenge</span> 并行收集器，采用复制算法，关注系统吞吐量</p>
<p><span style="font-weight: bold;">G1收集器(整个Java堆：包括新生代和老年代)</span></p>
<blockquote>
<p style="margin-bottom: 25px; line-height: 1.7;"><span style="font-weight: bold;">特点</span></p>
<p style="margin-bottom: 25px; line-height: 1.7;"><span style="font-weight: bold;">并行与并发</span></p>
<p style="margin-bottom: 25px; line-height: 1.7;"><span style="font-weight: bold;">分代收集</span>（仍然保留了分代的概念）</p>
<p style="margin-bottom: 25px; line-height: 1.7;">空间整合（整体上属于“标记-整理”算法，<span style="font-weight: bold;">不会导致空间碎片</span>）</p>
<p style="line-height: 1.7;"><span style="font-weight: bold;">可预测的停顿</span>（比CMS更先进的地方在于能让使用者明确指定一个长度为M毫秒的时间片段内，消耗在垃圾收集上的时间不得超过N毫秒）</p>
</blockquote>
<p><span style="font-weight: bold;">Serial Old</span> serial的老年代版本，采用标记整理算法 单线程</p>
<p><span style="font-weight: bold;">Parallel Old</span> Parallel Scavenge的老年代版本，采用标记整理算法 多线程</p>
<p><span style="font-weight: bold;">CMS收集器</span> 以最小回收时间停顿为目标的并发回收器，采用标记清除算法</p>
<p><span style="font-weight: bold;">垃圾收集器一览表</span></p>
<table>
<tr>
名称
收集目标
算法
线程支持
其他
</tr>

<tr>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">Serial</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">新生代</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">复制算法</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">单线程</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">单线程收集器</td>
</tr>
<tr>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">Serial Old</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">老年代</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">标记整理算法</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">单线程</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">Serial的老年代版本</td>
</tr>
<tr>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">ParNew</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">新生代</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">复制算法</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">多线程</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">Serial收集器的多线程版本,可与CMS配合使用</td>
</tr>
<tr>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">Parallel Scavenge</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">新生代</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">复制算法</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">多线程</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">类似ParNew收集器，更关注系统吞吐量</td>
</tr>
<tr>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">Parallel Old</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">老年代</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">标记整理算法</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">多线程</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">与Parallel Scavenge收集器配合使用，特点：“吞吐量优先”，在注重吞吐量和CPU资源敏感的场合，都可以使用这个组合</td>
</tr>
<tr>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">CMS收集器</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">老年代</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">标记清除算法</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">多线程</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">以最小回收时间停顿为目标的并发回收器</td>
</tr>
<tr>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">G1</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">新生代、老年代</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">标记整理算法</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">多线程</td>
<td style="padding: 8px; border: 1px solid #dddddd; line-height: 20px; vertical-align: middle;">面向服务端的收集器，能充分利用CPU和多核环境； 并行与并发收集器，它能够建立可预测的停顿时间模型。</td>
</tr>

</table>
<p><span style="font-weight: bold;">参考:</span><br><a href="https://www.jianshu.com/p/9c87058a8509" style="background-color: transparent; color: #3194d0; cursor: pointer;" target="_blank">JVM垃圾回收算法</a><br><a href="https://www.jianshu.com/p/753efd60f329" style="background-color: transparent; color: #3194d0; cursor: pointer;" target="_blank">JVM重要知识点整理和学习</a><br><a href="https://www.jianshu.com/p/b572f69a1b93" style="background-color: transparent; color: #3194d0; cursor: pointer;" target="_blank">JVM垃圾回收算法和垃圾收集器</a></p>
</div>
              
              <br/><br/>
              <span style="color:red;">
                <a href="https://www.iteye.com/blog/java8988-2428695#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
              </span>
              <br/><br/><br/>
<span style="color:#E28822;">ITeye推荐</span>
<br/>
<ul><li><a href='/clicks/433' target='_blank'><span style="color:red;font-weight:bold;">—软件人才免语言低担保 赴美带薪读研！— </span></a></li></ul>
<br/><br/><br/>
              ]]>
            </description>
            <pubDate>Tue, 14 Aug 2018 15:38:23 +0800</pubDate>
            <link>https://www.iteye.com/blog/user/java8988/blog/2428695</link>
            <guid isPermaLink="false">https://www.iteye.com/blog/user/java8988/blog/2428695</guid>
          </item>
                  <item>
            <title>分布式锁原理及实现</title>
            <description>
              <![CDATA[
              <div class="iteye-blog-content-contain" style="font-size: 14px;">
<h2>什么是分布式锁？</h2>
<p>控制分布式架构中多个模块访问的优先级</p>
<p>要介绍分布式锁，首先要提到与分布式锁相对应的是线程锁、进程锁。</p>
<p>线程锁：主要用来给方法、代码块加锁。当某个方法或代码使用锁，在同一时刻仅有一个线程执行该方法或该代码段。线程锁只在同一JVM中有效果，因为线程锁的实现在根本上是依靠线程之间共享内存实现的，比如synchronized是共享对象头，显示锁Lock是共享某个变量（state）。</p>
<p>进程锁：为了控制同一操作系统中多个进程访问某个共享资源，因为进程具有独立性，各个进程无法访问其他进程的资源，因此无法通过synchronized等线程锁实现进程锁。</p>
<p>分布式锁：当多个进程不在同一个系统中，用分布式锁控制多个进程对资源的访问。</p>
<h2>分布式锁实现方式</h2>
<h3>1.基于数据库实现分布式锁</h3>
<h4>基于数据库表</h4>
<p>往数据库中插入数据，插入成功获取访问资源的锁，访问完成，删除数据库中对应的记录，释放访问资源的锁<br>要实现分布式锁，最简单的方式可能就是直接创建一张锁表，然后通过操作该表中的数据来实现了。</p>
<p>当我们要锁住某个方法或资源时，我们就在该表中增加一条记录，想要释放锁的时候就删除这条记录。</p>
<p>创建这样一张数据库表：</p>
<div class="image-package">
<div class="image-container" style="background-color: transparent; margin: 0px auto; max-width: 700px;">
<div class="image-container-fill"> </div>
<div class="image-view" style="width: 700px; height: 165.125px; overflow: hidden;"><img alt="" src="https://upload-images.jianshu.io/upload_images/11336294-36480d0f76d6d888?imageMogr2/auto-orient/strip%7CimageView2/2/w/700"></div>
</div>
<div class="image-caption" style="min-width: 20%; max-width: 80%; display: inline-block; padding: 10px; margin: 0px auto; border-bottom: 1px solid #d9d9d9; font-size: 14px; color: #969696; line-height: 1.7;">image</div>
</div>
<p><br><span>当我们想要锁住某个方法时，执行以下SQL：</span></p>
<div class="image-package">
<div class="image-container" style="background-color: transparent; margin: 0px auto; max-width: 700px;">
<div class="image-container-fill"> </div>
<div class="image-view" style="width: 700px; height: 22.4688px; overflow: hidden;"><img alt="" src="https://upload-images.jianshu.io/upload_images/11336294-b91bff02a03a2ade?imageMogr2/auto-orient/strip%7CimageView2/2/w/700"></div>
</div>
<div class="image-caption" style="min-width: 20%; max-width: 80%; display: inline-block; padding: 10px; margin: 0px auto; border-bottom: 1px solid #d9d9d9; font-size: 14px; color: #969696; line-height: 1.7;">image</div>
</div>
<p><br><span>创建表示我们对method_name做了唯一性约束，这里如果有多个请求同时提交到数据库的话，数据库会保证只有一个操作可以成功，那么我们就可以认为操作成功的那个线程获得了该方法的锁</span><br><span>当方法执行完毕之后，想要释放锁的话，需要执行以下Sql:</span></p>
<div class="image-package">
<div class="image-container" style="background-color: transparent; margin: 0px auto; max-width: 700px;">
<div class="image-container-fill"> </div>
<div class="image-view" style="width: 700px; height: 18.1875px; overflow: hidden;"><img alt="" src="https://upload-images.jianshu.io/upload_images/11336294-442f2d864d55a769?imageMogr2/auto-orient/strip%7CimageView2/2/w/700"></div>
</div>
<div class="image-caption" style="min-width: 20%; max-width: 80%; display: inline-block; padding: 10px; margin: 0px auto; border-bottom: 1px solid #d9d9d9; font-size: 14px; color: #969696; line-height: 1.7;">image</div>
</div>
<p><br><span>上面这种实现有以下几个问题：</span><br><span>1、这把锁强依赖数据库的可用性，数据库是一个单点，一旦数据库挂掉，会导致业务系统不可用。</span></p>
<p> </p>
<p>2、这把锁没有失效时间，一旦解锁操作失败，就会导致锁记录一直在数据库中，其他线程无法再获得到锁。</p>
<p>3、这把锁只能是非阻塞的，因为数据的insert操作，一旦插入失败就会直接报错。没有获得锁的线程并不会进入排队队列，要想再次获得锁就要再次触发获得锁操作。</p>
<p>4、这把锁是非重入的，同一个线程在没有释放锁之前无法再次获得该锁。因为数据中数据已经存在了。<br>解决方法：</p>
<ol>
<li style="line-height: 30px;">数据库是单点？搞两个数据库，数据之前双向同步。一旦挂掉快速切换到备库上</li>
<li style="line-height: 30px;">没有失效时间？只要做一个定时任务，每隔一定时间把数据库中的超时数据清理一遍。</li>
<li style="line-height: 30px;">非阻塞的？搞一个while循环，直到insert成功再返回成功。</li>
<li style="line-height: 30px;">非重入的？在数据库表中加个字段，记录当前获得锁的机器的主机信息和线程信息，那么下次再获取锁的时候先查询数据库，如果当前机器的主机信息和线程信息在数据库可以查到的话，直接把锁分配给他就可以了。</li>
</ol>
<h3>存在的问题：</h3>
<ul>
<li style="line-height: 30px;">删除记录失败，会导致其他进程无法获取访问资源的锁</li>
<li style="line-height: 30px;">insert记录并不是重入锁</li>
</ul>
<h3>解决方法：</h3>
<p>判断当前获取的锁是不是当前节点的<br>每个节点或者进程加一个id，删除失败获取节点的id是不是等于当前节点的id，是的话，可以继续去做，即可重入锁</p>
<h4>基于数据库排他锁</h4>
<p>除了可以通过增删操作数据表中的记录以外，其实还可以借助数据中自带的锁来实现分布式的锁。</p>
<p>我们还用刚刚创建的那张数据库表。可以通过数据库的排他锁来实现分布式锁。 基于MySql的InnoDB引擎，可以使用以下方法来实现加锁操作：</p>
<p> </p>
<div class="image-package">
<div class="image-container" style="background-color: transparent; margin: 0px auto; max-width: 700px;">
<div class="image-container-fill"> </div>
<div class="image-view" style="width: 700px; height: 274.609px; overflow: hidden;"><img alt="" src="https://upload-images.jianshu.io/upload_images/11336294-b407733e440076d2?imageMogr2/auto-orient/strip%7CimageView2/2/w/700"></div>
</div>
<div class="image-caption" style="min-width: 20%; max-width: 80%; display: inline-block; padding: 10px; margin: 0px auto; border-bottom: 1px solid #d9d9d9; font-size: 14px; color: #969696; line-height: 1.7;">image</div>
</div>
<p> </p>
<p>在查询语句后面增加for update，数据库会在查询过程中给数据库表增加排他锁（这里再多提一句，InnoDB引擎在加锁的时候，只有通过索引进行检索的时候才会使用行级锁，否则会使用表级锁。这里我们希望使用行级锁，就要给method_name添加索引，值得注意的是，这个索引一定要创建成唯一索引，否则会出现多个重载方法之间无法同时被访问的问题。重载方法的话建议把参数类型也加上。）。当某条记录被加上排他锁之后，其他线程无法再在该行记录上增加排他锁。</p>
<p>我们可以认为获得排它锁的线程即可获得分布式锁，当获取到锁之后，可以执行方法的业务逻辑，执行完方法之后，再通过以下方法解锁：</p>
<p> </p>
<div class="image-package">
<div class="image-container" style="background-color: transparent; margin: 0px auto; max-width: 700px;">
<div class="image-container-fill"> </div>
<div class="image-view" style="width: 700px; height: 56.2031px; overflow: hidden;"><img alt="" src="https://upload-images.jianshu.io/upload_images/11336294-cfcfc495117d92f9?imageMogr2/auto-orient/strip%7CimageView2/2/w/700"></div>
</div>
<div class="image-caption" style="min-width: 20%; max-width: 80%; display: inline-block; padding: 10px; margin: 0px auto; border-bottom: 1px solid #d9d9d9; font-size: 14px; color: #969696; line-height: 1.7;">image</div>
</div>
<p> </p>
<p>通过connection.commit()操作来释放锁。<br>这种方法可以有效的解决上面提到的无法释放锁和阻塞锁的问题。</p>
<p>阻塞锁？ for update语句会在执行成功后立即返回，在执行失败时一直处于阻塞状态，直到成功。<br>锁定之后服务宕机，无法释放？使用这种方式，服务宕机之后数据库会自己把锁释放掉。<br>但是还是无法直接解决数据库单点和可重入问题。</p>
<p>这里还可能存在另外一个问题，虽然我们对method_name 使用了唯一索引，并且显示使用for update来使用行级锁。但是，MySql会对查询进行优化，即便在条件中使用了索引字段，但是否使用索引来检索数据是由 MySQL 通过判断不同执行计划的代价来决定的，如果 MySQL 认为全表扫效率更高，比如对一些很小的表，它就不会使用索引，这种情况下 InnoDB 将使用表锁，而不是行锁。如果发生这种情况就悲剧了</p>
<h3>2. 基于Zookeeper实现分布式锁</h3>
<p>ZooKeeper是一个为分布式应用提供一致性服务的开源组件，它内部是一个分层的文件系统目录树结构，规定同一个目录下只能有一个唯一文件名。基于ZooKeeper实现分布式锁的步骤如下：</p>
<p>（1）创建一个目录mylock；<br>（2）线程A想获取锁就在mylock目录下创建临时顺序节点；<br>（3）获取mylock目录下所有的子节点，然后获取比自己小的兄弟节点，如果不存在，则说明当前线程顺序号最小，获得锁；<br>（4）线程B获取所有节点，判断自己不是最小节点，设置监听比自己次小的节点；<br>（5）线程A处理完，删除自己的节点，线程B监听到变更事件，判断自己是不是最小的节点，如果是则获得锁。<br>可以直接使用zookeeper第三方库Curator客户端，这个客户端中封装了一个可重入的锁服务。</p>
<div class="image-package">
<div class="image-container" style="background-color: transparent; margin: 0px auto; max-width: 700px;">
<div class="image-container-fill"> </div>
<div class="image-view" style="width: 700px; height: 329.969px; overflow: hidden;"><img alt="" src="https://upload-images.jianshu.io/upload_images/11336294-b2c2c724e1d48b28?imageMogr2/auto-orient/strip%7CimageView2/2/w/700"></div>
</div>
<div class="image-caption" style="min-width: 20%; max-width: 80%; display: inline-block; padding: 10px; margin: 0px auto; border-bottom: 1px solid #d9d9d9; font-size: 14px; color: #969696; line-height: 1.7;">image</div>
</div>
<p> </p>
<p>Curator提供的InterProcessMutex是分布式锁的实现。acquire方法用户获取锁，release方法用于释放锁。</p>
<p>使用ZK实现的分布式锁好像完全符合了本文开头我们对一个分布式锁的所有期望。但是，其实并不是，Zookeeper实现的分布式锁其实存在一个缺点，那就是性能上可能并没有缓存服务那么高。因为每次在创建锁和释放锁的过程中，都要动态创建、销毁瞬时节点来实现锁功能。ZK中创建和删除节点只能通过Leader服务器来执行，然后将数据同不到所有的Follower机器上。</p>
<p>其实，使用Zookeeper也有可能带来并发问题，只是并不常见而已。考虑这样的情况，由于网络抖动，客户端可ZK集群的session连接断了，那么zk以为客户端挂了，就会删除临时节点，这时候其他客户端就可以获取到分布式锁了。就可能产生并发问题。这个问题不常见是因为zk有重试机制，一旦zk集群检测不到客户端的心跳，就会重试，Curator客户端支持多种重试策略。多次重试之后还不行的话才会删除临时节点。（所以，选择一个合适的重试策略也比较重要，要在锁的粒度和并发之间找一个平衡。）</p>
<h3>3.基于缓存实现分布式锁</h3>
<p>setnx</p>
<h2>三种方案的比较</h2>
<p>上面几种方式，哪种方式都无法做到完美。就像CAP一样，在复杂性、可靠性、性能等方面无法同时满足，所以，根据不同的应用场景选择最适合自己的才是王道。<br><span style="font-weight: bold;">从理解的难易程度角度（从低到高）</span><br>数据库 &gt; 缓存 &gt; Zookeeper<br><span style="font-weight: bold;">从实现的复杂性角度（从低到高）</span><br>Zookeeper &gt;= 缓存 &gt; 数据库<br><span style="font-weight: bold;">从性能角度（从高到低）</span><br>缓存 &gt; Zookeeper &gt;= 数据库<br><span style="font-weight: bold;">从可靠性角度（从高到低）</span><br>Zookeeper &gt; 缓存 &gt; 数据库<br><span style="font-weight: bold;">参考：</span></p>
<p><span style="font-weight: bold;"><a href="https://www.cnblogs.com/austinspark-jessylu/p/8043726.html" style="" target="_blank">分布式锁的几种实现方式</a><br style=""><a href="https://blog.csdn.net/xlgen157387/article/details/79036337" style="" target="_blank">分布式锁简单入门以及三种实现方式介绍</a><br style=""><a href="https://blog.csdn.net/l_bestcoder/article/details/79336986" style="" target="_blank">分布式锁的作用及实现（Redis）</a></span></p>
</div>
              
              <br/><br/>
              <span style="color:red;">
                <a href="https://www.iteye.com/blog/java8988-2428432#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
              </span>
              <br/><br/><br/>
<span style="color:#E28822;">ITeye推荐</span>
<br/>
<ul><li><a href='/clicks/433' target='_blank'><span style="color:red;font-weight:bold;">—软件人才免语言低担保 赴美带薪读研！— </span></a></li></ul>
<br/><br/><br/>
              ]]>
            </description>
            <pubDate>Fri, 10 Aug 2018 00:11:11 +0800</pubDate>
            <link>https://www.iteye.com/blog/user/java8988/blog/2428432</link>
            <guid isPermaLink="false">https://www.iteye.com/blog/user/java8988/blog/2428432</guid>
          </item>
                  <item>
            <title>redis入门常见问题</title>
            <description>
              <![CDATA[
              <div class="iteye-blog-content-contain" style="font-size: 14px;">
<p>spring集成redis遇到的一些问题</p>
<p>1.Error creating bean with name 'enableRedisKeyspaceNotificationsInitializer' defined in class path resource 好像看不出报的什么错，继续往下看详细信息</p>
<pre name="code" class="java">org.springframework.beans.factory.BeanCreationException: Error creating bean with name 
'enableRedisKeyspaceNotificationsInitializer' defined in class path resource 
[org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfiguration.class]: 
Invocation of init method failed; 
nested exception is java.lang.IllegalStateException: Unable to configure Redis to keyspace notifications. 
See http://docs.spring.io/spring-session/docs/current/reference/html5/#api-redisoperationssessionrepository-sessiondestroyedevent</pre>
<p> 详细报错信息如下：</p>
<p> </p>
<pre name="code" class="java">23:30:46.489 [RMI TCP Connection(5)-127.0.0.1] ERROR org.springframework.web.servlet.DispatcherServlet - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'enableRedisKeyspaceNotificationsInitializer' defined in class path resource [org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfiguration.class]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: Unable to configure Redis to keyspace notifications. See http://docs.spring.io/spring-session/docs/current/reference/html5/#api-redisoperationssessionrepository-sessiondestroyedevent
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1710)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:583)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:502)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:312)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:310)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:760)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:868)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549)
	at org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:676)
	at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:642)
	at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:690)
	at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:558)
	at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:499)
	at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:172)
	at javax.servlet.GenericServlet.init(GenericServlet.java:160)
	at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1280)
	at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1193)
	at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1088)
	at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:5123)
	at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5407)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
	at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901)
	at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877)
	at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:633)
	at org.apache.catalina.startup.HostConfig.manageApp(HostConfig.java:1552)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:301)
	at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819)
	at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801)
	at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:622)
	at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:569)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:301)
	at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819)
	at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801)
	at javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1468)
	at javax.management.remote.rmi.RMIConnectionImpl.access$300(RMIConnectionImpl.java:76)
	at javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1309)
	at javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1401)
	at javax.management.remote.rmi.RMIConnectionImpl.invoke(RMIConnectionImpl.java:829)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:324)
	at sun.rmi.transport.Transport$1.run(Transport.java:200)
	at sun.rmi.transport.Transport$1.run(Transport.java:197)
	at java.security.AccessController.doPrivileged(Native Method)
	at sun.rmi.transport.Transport.serviceCall(Transport.java:196)
	at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:568)
	at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:826)
	at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:683)
	at java.security.AccessController.doPrivileged(Native Method)
	at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:682)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.IllegalStateException: Unable to configure Redis to keyspace notifications. See http://docs.spring.io/spring-session/docs/current/reference/html5/#api-redisoperationssessionrepository-sessiondestroyedevent
	at org.springframework.session.data.redis.config.ConfigureNotifyKeyspaceEventsAction.getNotifyOptions(ConfigureNotifyKeyspaceEventsAction.java:83)
	at org.springframework.session.data.redis.config.ConfigureNotifyKeyspaceEventsAction.configure(ConfigureNotifyKeyspaceEventsAction.java:57)
	at org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration$EnableRedisKeyspaceNotificationsInitializer.afterPropertiesSet(RedisHttpSessionConfiguration.java:286)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1769)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1706)
	... 64 common frames omitted
Caused by: org.springframework.dao.InvalidDataAccessApiUsageException: DENIED Redis is running in protected mode because protected mode is enabled, no bind address was specified, no authentication password is requested to clients. In this mode connections are only accepted from the loopback interface. If you want to connect from external computers to Redis you may adopt one of the following solutions: 1) Just disable protected mode sending the command 'CONFIG SET protected-mode no' from the loopback interface by connecting to Redis from the same host the server is running, however MAKE SURE Redis is not publicly accessible from internet if you do so. Use CONFIG REWRITE to make this change permanent. 2) Alternatively you can just disable the protected mode by editing the Redis configuration file, and setting the protected mode option to 'no', and then restarting the server. 3) If you started the server manually just for testing, restart it with the '--protected-mode no' option. 4) Setup a bind address or an authentication password. NOTE: You only need to do one of the above things in order for the server to start accepting connections from the outside.; nested exception is redis.clients.jedis.exceptions.JedisDataException: DENIED Redis is running in protected mode because protected mode is enabled, no bind address was specified, no authentication password is requested to clients. In this mode connections are only accepted from the loopback interface. If you want to connect from external computers to Redis you may adopt one of the following solutions: 1) Just disable protected mode sending the command 'CONFIG SET protected-mode no' from the loopback interface by connecting to Redis from the same host the server is running, however MAKE SURE Redis is not publicly accessible from internet if you do so. Use CONFIG REWRITE to make this change permanent. 2) Alternatively you can just disable the protected mode by editing the Redis configuration file, and setting the protected mode option to 'no', and then restarting the server. 3) If you started the server manually just for testing, restart it with the '--protected-mode no' option. 4) Setup a bind address or an authentication password. NOTE: You only need to do one of the above things in order for the server to start accepting connections from the outside.
	at org.springframework.data.redis.connection.jedis.JedisExceptionConverter.convert(JedisExceptionConverter.java:64)
	at org.springframework.data.redis.connection.jedis.JedisExceptionConverter.convert(JedisExceptionConverter.java:41)
	at org.springframework.data.redis.PassThroughExceptionTranslationStrategy.translate(PassThroughExceptionTranslationStrategy.java:44)
	at org.springframework.data.redis.FallbackExceptionTranslationStrategy.translate(FallbackExceptionTranslationStrategy.java:42)
	at org.springframework.data.redis.connection.jedis.JedisConnection.convertJedisAccessException(JedisConnection.java:181)
	at org.springframework.data.redis.connection.jedis.JedisServerCommands.convertJedisAccessException(JedisServerCommands.java:531)
	at org.springframework.data.redis.connection.jedis.JedisServerCommands.getConfig(JedisServerCommands.java:299)
	at org.springframework.data.redis.connection.DefaultedRedisConnection.getConfig(DefaultedRedisConnection.java:1119)
	at org.springframework.session.data.redis.config.ConfigureNotifyKeyspaceEventsAction.getNotifyOptions(ConfigureNotifyKeyspaceEventsAction.java:76)
	... 68 common frames omitted
<span style="color: #000000;">Caused by: redis.clients.jedis.exceptions.JedisDataException: DENIED Redis is running in protected mode because protected mode is enabled, no bind address was specified, no authentication password is requested to clients. In this mode connections are only accepted from the loopback interface. If you want to connect from external computers to Redis you may adopt one of the following solutions: 1) Just disable protected mode sending the command 'CONFIG SET protected-mode no' from the loopback interface by connecting to Redis from the same host the server is running, however MAKE SURE Redis is not publicly accessible from internet if you do so. Use CONFIG REWRITE to make this change permanent. 2) Alternatively you can just disable the protected mode by editing the Redis configuration file, and setting the protected mode option to 'no', and then restarting the server. 3) If you started the server manually just for testing, restart it with the '--protected-mode no' option. 4) Setup a bind address or an authentication password. NOTE: You only need to do one of the above things in order for the server to start accepting connections from the outside.
</span>	at redis.clients.jedis.Protocol.processError(Protocol.java:127)
	at redis.clients.jedis.Protocol.process(Protocol.java:161)
	at redis.clients.jedis.Protocol.read(Protocol.java:215)
	at redis.clients.jedis.Connection.readProtocolWithCheckingBroken(Connection.java:340)
	at redis.clients.jedis.Connection.getBinaryMultiBulkReply(Connection.java:276)
	at redis.clients.jedis.Connection.getMultiBulkReply(Connection.java:269)
	at redis.clients.jedis.Jedis.configGet(Jedis.java:2630)
	at org.springframework.data.redis.connection.jedis.JedisServerCommands.getConfig(JedisServerCommands.java:297)
	... 70 common frames omitted</pre>
<p> 86行，DENIED Redis is running in protected mode because protected mode is enabled, no bind address was specified, no authentication password is requested to clients.由于启用了保护模式，没有指定绑定地址，也没有向客户端请求身份验证密码，因此拒绝redis在保护模式下运行。</p>
<p> </p>
<p>解决方案：</p>
<p><span style="font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 12px;">修改配置文件redis.conf</span></p>
<p> </p>
<pre name="code" class="ruby"># accept connections only from clients running into the same computer it
# is running).
#
# IF YOU ARE SURE YOU WANT YOUR INSTANCE TO LISTEN TO ALL THE INTERFACES
# JUST COMMENT THE FOLLOWING LINE.
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<span style="font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 12px;">#bind 127.0.0.1</span>

# Protected mode is a layer of security protection, in order to avoid that
# Redis instances left open on the internet are accessed and exploited.
#
# When protected mode is on and if:
#
# 1) The server is not binding explicitly to a set of addresses using the
#    "bind" directive.
# 2) No password is configured.
#
# The server only accepts connections from clients connecting from the
# IPv4 and IPv6 loopback addresses 127.0.0.1 and ::1, and from Unix domain
# sockets.
#
# By default protected mode is enabled. You should disable it only if
# you are sure you want clients from other hosts to connect to Redis
# even if no authentication is configured, nor a specific set of interfaces
# are explicitly listed using the "bind" directive.
<span style="font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 12px;">protected-mode no</span>

# Accept connections on the specified port, default is 6379 (IANA #815344).
# If port 0 is specified Redis will not listen on a TCP socket.
port 6379

# TCP listen() backlog.
#
# In high requests-per-second environments you need an high backlog in order
# to avoid slow clients connections issues. Note that the Linux kernel
# will silently truncate it to the value of /proc/sys/net/core/somaxconn so
# make sure to raise both the value of somaxconn and tcp_max_syn_backlog
</pre>
<p> 如上 注释 bind 127.0.0.1</p>
<p>将 protected-mode yes 改为 protected-mode no</p>
<p>2.redis启动</p>
<p><span style="color: #333333; font-family: 微软雅黑, Arial, sans-serif;">通过启动参数告诉redis使用指定配置文件使用下面命令启动。</span></p>
<pre name="code" class="ruby">[root@eth-01 redis-3.2.8]# ./src/redis-server redis.conf</pre>
<p> <span style="color: #333333; font-family: 微软雅黑, Arial, sans-serif;">redis.conf是一个默认的配置文件。我们可以根据需要使用自己的配置文件。</span></p>
<p> </p>
<p> </p>
<p><span style="color: #333333; font-family: 微软雅黑, Arial, sans-serif;">redis入门网站：</span></p>
<p><span style="color: #333333; font-family: 微软雅黑, Arial, sans-serif;">官方网站：https://redis.io/</span></p>
<p><span style="color: #333333; font-family: 微软雅黑, Arial, sans-serif;">中文网站：http://www.redis.net.cn/</span></p>
<p><span style="color: #333333; font-family: 微软雅黑, Arial, sans-serif;">http://www.redis.cn/</span></p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
</div>
              
              <br/><br/>
              <span style="color:red;">
                <a href="https://www.iteye.com/blog/java8988-2426616#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
              </span>
              <br/><br/><br/>
<span style="color:#E28822;">ITeye推荐</span>
<br/>
<ul><li><a href='/clicks/433' target='_blank'><span style="color:red;font-weight:bold;">—软件人才免语言低担保 赴美带薪读研！— </span></a></li></ul>
<br/><br/><br/>
              ]]>
            </description>
            <pubDate>Wed, 11 Jul 2018 00:04:17 +0800</pubDate>
            <link>https://www.iteye.com/blog/user/java8988/blog/2426616</link>
            <guid isPermaLink="false">https://www.iteye.com/blog/user/java8988/blog/2426616</guid>
          </item>
                  <item>
            <title>MAC IDEA自动生成SerialVersionUID</title>
            <description>
              <![CDATA[
              <div class="iteye-blog-content-contain" style="font-size: 14px;">
<p>换了mac电脑，依据windows下idea的设置，依次File--&gt;Othering Settings--&gt;Default Settings <span style="color: #333333; font-family: 'PingFang SC', 'Microsoft YaHei', SimHei, Arial, SimSun;">-&gt;Inspections-&gt;Serialization issues，将serialzable class without "serialVersionUID"打上勾，Apply之后，</span><span style="color: #4f4f4f; font-family: 'PingFang SC', 'Microsoft YaHei', SimHei, Arial, SimSun; font-size: 16px; text-align: justify;">选中类名，按atl＋enter键，依旧不会提示生成serialVersionUID；</span></p>
<p><span style="color: #4f4f4f; font-family: 'PingFang SC', 'Microsoft YaHei', SimHei, Arial, SimSun; font-size: 16px; text-align: justify;">其实mac下提示生成</span><span style="color: #4f4f4f; font-family: 'PingFang SC', 'Microsoft YaHei', SimHei, Arial, SimSun; font-size: 16px; text-align: justify;">serialVersionUID的方式如下(亲测可用)：</span></p>
<p><span><span style="color: #ff0000;">Mac版本是设置Preferences</span>，具体步骤如下：</span></p>
<p><span>IntelliJ IDEA--&gt;Preferences--&gt;Inspections--&gt;Java--&gt;</span><span style="font-family: 'PingFang SC', 'Microsoft YaHei', SimHei, Arial, SimSun;">Serialization issues,</span><span style="font-family: 'PingFang SC', 'Microsoft YaHei', SimHei, Arial, SimSun;">将serialzable class without "serialVersionUID"打上勾</span></p>
<p><span style="font-family: 'PingFang SC', 'Microsoft YaHei', SimHei, Arial, SimSun;"><br><img alt="" src="http://dl2.iteye.com/upload/attachment/0130/0518/b0c44e00-8465-315f-bd0a-9744539b914b.png"><br> <br><img alt="" src="http://dl2.iteye.com/upload/attachment/0130/0520/4107b01a-945d-309b-a85b-0fbc10debca1.png"><br> </span></p>
<p><span style="font-family: 'PingFang SC', 'Microsoft YaHei', SimHei, Arial, SimSun;">如若有误，欢迎留言指正</span></p>
<p><span> </span></p>
<p> </p>
</div>
              
              <br/><br/>
              <span style="color:red;">
                <a href="https://www.iteye.com/blog/java8988-2424858#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
              </span>
              <br/><br/><br/>
<span style="color:#E28822;">ITeye推荐</span>
<br/>
<ul><li><a href='/clicks/433' target='_blank'><span style="color:red;font-weight:bold;">—软件人才免语言低担保 赴美带薪读研！— </span></a></li></ul>
<br/><br/><br/>
              ]]>
            </description>
            <pubDate>Wed, 13 Jun 2018 09:03:46 +0800</pubDate>
            <link>https://www.iteye.com/blog/user/java8988/blog/2424858</link>
            <guid isPermaLink="false">https://www.iteye.com/blog/user/java8988/blog/2424858</guid>
          </item>
          </channel>
</rss>
