<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.9.0">Jekyll</generator><link href="https://sunbufu.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://sunbufu.github.io/" rel="alternate" type="text/html" /><updated>2021-05-10T21:38:20+08:00</updated><id>https://sunbufu.github.io/feed.xml</id><title type="html">孙不服的博客</title><subtitle>孙不服的博客</subtitle><author><name>sunbufu</name></author><entry><title type="html">一个小周日</title><link href="https://sunbufu.github.io/2020/09/13/sunday/" rel="alternate" type="text/html" title="一个小周日" /><published>2020-09-13T00:00:00+08:00</published><updated>2020-09-13T00:00:00+08:00</updated><id>https://sunbufu.github.io/2020/09/13/sunday</id><content type="html" xml:base="https://sunbufu.github.io/2020/09/13/sunday/">&lt;p&gt;好长时间没有更新博客了，没有写点东西了，趁有点时间，随便写写近来生活和工作的感触吧。想到哪里写到哪里，也挺好的。&lt;/p&gt;

&lt;p&gt;今天心情不错，算是入职头条以来难得的一个好周日，头条是大小周，每两周才有这么一次休息的周日。加上孙彩云难得不在家，所以更是显得格外可贵。虽然窗外一直传来汽车的鸣笛和隔壁小区施工的噪声，但却不怎么感觉到吵闹，也有不知名的小鸟站在邻居空调的外置机上，喳喳喳喳，也听不懂他们在说些什么，反正看起来很热闹，倒是家里的小猫咪有点按耐不住，想跟他们谈谈鸟生或者猫生。&lt;/p&gt;

&lt;p&gt;恰逢夏秋交接，天气逐渐的转凉了，晚上打开窗户，不盖被子的时候都会被冻醒。但是白天更是一种享受，温度不冷不热，阳光从窗户斜斜的照进来，刚好可以在我一扭头可以看到的地方，提醒我外面的生活也很美好。我也想出去走走，但是孙彩云不在，一个人逛悠起来也没啥意思。跟着自己的思路随便想想，不去考虑那些工作上的压力，不去追逐生活中的烦恼，挺好。我起身去拉上了窗帘，窗户上的阳光映的电脑屏幕都快看不见了，一扭头小猫咪躺在我椅子后面的地板上，哼，这么粘人。&lt;/p&gt;

&lt;p&gt;天气预报说可能会有小雨，天上还的确有那么几朵云。孙彩云买了个香薰，但是我的鼻子却不怎么灵敏，一直也没有闻到什么香味。昨天她临走的时候还点了起来，说要给我熏熏，出了门我就给吹了，我怕待会玩起来忘了。我这个人就是这样，总是被一些乱七八糟的东西填满，特别是一些鸡毛蒜皮的小烦恼，都会搞得我浑身难受，恨不得能立马把烦恼解决。我把手机锁屏签名改成了“本来无一物，何处惹尘埃”，但是看来没怎么有效果。今年开始一直再用滴答清单，好像是挺管用的，把要做和计划做的事情，和一些乱七八糟的烦恼，都写进去，可以的就设置个提醒时间，然后就尽量不要去想了。想的事情太多，反而一件事都做不了了。&lt;/p&gt;

&lt;p&gt;头条的工作怎么说呢，的确是挺忙的。不管是工作的任务，还是工作的氛围，还是大家的工作方式，感觉就像是处在一个急湍的河水中，你刚想停下歇歇脚，身后的水流又推着你到了下一个转弯。这么说起来，还是挺怀念瓜子悠闲的时光的，嘿嘿。&lt;/p&gt;

&lt;p&gt;我买了个小米手环，想记录下自己睡眠的状况，爸妈老担心我睡眠不足，身体不好。我自己倒是没有什么感觉，反正督促下自己注意身体吧。说起来我们可能要搬家了，尽量去一个离公司近的地方，应该能节省下不少上下班通勤的时间。但是睡觉睡多了，也会困。&lt;/p&gt;

&lt;p&gt;最近好多认识的朋友、同学都要结婚了。大大小小的也都到了该成家的年纪，该背负的肯定还是要背的。最让我感到意外的是大改同学了，发展的贼迅速，也许是考虑了很多吧。&lt;/p&gt;

&lt;p&gt;刚才吹来了一阵风，小猫咪哇哇哇哇的跑了吹去，就先写到这里吧，去找个电影看看。&lt;/p&gt;</content><author><name>sunbufu</name></author><category term="life" /><summary type="html">好长时间没有更新博客了，没有写点东西了，趁有点时间，随便写写近来生活和工作的感触吧。想到哪里写到哪里，也挺好的。</summary></entry><entry><title type="html">bookkeeping 使用教程</title><link href="https://sunbufu.github.io/2020/05/02/bookkeeping/" rel="alternate" type="text/html" title="bookkeeping 使用教程" /><published>2020-05-02T00:00:00+08:00</published><updated>2020-05-02T00:00:00+08:00</updated><id>https://sunbufu.github.io/2020/05/02/bookkeeping</id><content type="html" xml:base="https://sunbufu.github.io/2020/05/02/bookkeeping/">&lt;h1 id=&quot;一-介绍&quot;&gt;一 介绍&lt;/h1&gt;

&lt;p&gt;一款开源永久免费的 webdav 记账 app &lt;br /&gt;
开源地址：&lt;a href=&quot;https://github.com/sunbufu/bookkeeping&quot;&gt;https://github.com/sunbufu/bookkeeping&lt;/a&gt;&lt;br /&gt;
酷安地址：&lt;a href=&quot;https://www.coolapk.com/apk/261672&quot;&gt;https://www.coolapk.com/apk/261672&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;特点：&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;开源且永久免费，欢迎监督，也欢迎 issue 和 pr&lt;/li&gt;
  &lt;li&gt;不申请多余权限，后台纯净&lt;/li&gt;
  &lt;li&gt;完全依赖 webdav，没有其他服务器，不会滥用用户数据&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;之前一直在使用圈子账本，刚开始还挺好，后来的广告越来越多，启动越来越慢，各种地方想变现，有点恶心了。找了一圈没找到喜欢的 app，索性自己用 flutter 开发一个，开源并放在了 github 上。欢迎大家下载使用，也欢迎大家的意见，更欢迎大家 PR。&lt;/p&gt;

&lt;h1 id=&quot;二-配置&quot;&gt;二 配置&lt;/h1&gt;

&lt;p&gt;配置过程主要是对 webdav 的配置，我使用&lt;a href=&quot;https://www.jianguoyun.com/&quot;&gt;坚果云&lt;/a&gt;作为服务器，以下也以坚果云为例，其它服务类似。&lt;/p&gt;

&lt;h2 id=&quot;21-webdav-创建目录&quot;&gt;2.1 webdav 创建目录&lt;/h2&gt;
&lt;p&gt;首先需要在 webdav 服务器新建目录 bookkeeping，用于保存 app 配置和数据。
&lt;img src=&quot;https://sunbufu.github.io/images/2020/05/02/bookkeeping//webdav_create_directory.png&quot; alt=&quot;新建目录&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;22-创建-webdav-第三方账号&quot;&gt;2.2 创建 webdav 第三方账号&lt;/h2&gt;
&lt;p&gt;在【账户信息】&amp;gt;【安全选项】&amp;gt;【第三方应用管理】中新建账号，也可以参考坚果云&lt;a href=&quot;http://help.jianguoyun.com/?p=2064&quot;&gt;官方示例&lt;/a&gt;。
&lt;img src=&quot;https://sunbufu.github.io/images/2020/05/02/bookkeeping//webdav_create_account.png&quot; alt=&quot;新建账号&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;23-在-bookkeeping-中配置&quot;&gt;2.3 在 bookkeeping 中配置&lt;/h2&gt;
&lt;p&gt;点击右上角菜单中的设置账号。
&lt;img src=&quot;https://sunbufu.github.io/images/2020/05/02/bookkeeping//setting.png&quot; alt=&quot;设置&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;昵称：随便取&lt;/li&gt;
  &lt;li&gt;webdav url：webdav的地址【注意，此处需要加上目录名称，例如：https://dav.jianguoyun.com/dav/bookkeeping】&lt;/li&gt;
  &lt;li&gt;账号：webdav 的账户名&lt;/li&gt;
  &lt;li&gt;密码：webdav 的密码【注意，坚果云中需要点击”显示密码”复制出来】setting.png&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;至此，配置已经全部完成，enjoy it :)&lt;/p&gt;

&lt;h1 id=&quot;三-导入导出&quot;&gt;三 导入导出&lt;/h1&gt;

&lt;p&gt;TODO.&lt;/p&gt;

&lt;h1 id=&quot;四-关于&quot;&gt;四 关于&lt;/h1&gt;</content><author><name>sunbufu</name></author><category term="open source" /><summary type="html">一 介绍</summary></entry><entry><title type="html">2020年春季换工作的总结</title><link href="https://sunbufu.github.io/2020/05/01/about-job-hopping/" rel="alternate" type="text/html" title="2020年春季换工作的总结" /><published>2020-05-01T00:00:00+08:00</published><updated>2020-05-01T00:00:00+08:00</updated><id>https://sunbufu.github.io/2020/05/01/about-job-hopping</id><content type="html" xml:base="https://sunbufu.github.io/2020/05/01/about-job-hopping/">&lt;h1 id=&quot;一-背景介绍&quot;&gt;一 背景介绍&lt;/h1&gt;

&lt;p&gt;18 年加入瓜子，想来已经有两年多了，期间学到了很多，也收获了很多，感谢瓜子。但随着时间的流逝，我也变成了他们口中的”老人”，尤其是最后的那段时间，感觉项目失去了挑战，工作也没有了激情，俨然瓜子已经成了我”舒适区”的模样。人不都说嘛，要”敢于跳出自己的舒适区”，”生于忧患死于安乐”，所以我毅然决然的决定出来看看。&lt;br /&gt;
但是 20 注定是不平凡的一年，年初就遇到了新冠病毒，各个地方也实施了隔离、封城、停工停产等措施。很多依赖实体的企业也迫不得已断尾求生，裁员、降薪、停职也都纷纷拿到了台面上，让今年的面试更难了一些。&lt;br /&gt;
虽然如此，但是路还是要走，生活还是要继续，经过了一番苦战吧，最终有幸来到了字节跳动，今年的面试也算是一份特殊经历吧，因此写下来，算是对自己的一个总结吧。&lt;/p&gt;

&lt;h1 id=&quot;二-面试过程&quot;&gt;二 面试过程&lt;/h1&gt;

&lt;p&gt;既然目标（跳到一家心仪的公司）确定了，下一步就需要计划和准备了。我在网上看了一些面试的经验，大概把我的面试分成一下几个步骤：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;面试的准备&lt;br /&gt;
 准备大概可以分成三部分：自我介绍、项目、知识点、算法题和情景题。我的面试准备大概是从年前开始的吧，在网上找了一些资料，根据自己的理解，把知识点用思维导图的方式整理了一遍，后来在看项目的时候把项目也加了进去。但对于算法题和情景题我没有特别好的办法，就是日常的的时候多做做题，刷刷 lc，逛逛技术论坛吧。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;面试不是特别心仪的公司&lt;br /&gt;
 在面试中查缺补漏，及时找出自己知识的漏洞和盲区，特别是开发岗位，的确很难一上来就把所有的知识点都回忆起来，这也是我觉得这一步是非常有必要且重要的原因。对于我来说，毕业到今年面试之前总共也就面试了三四次，面试经验可以说是一点都没有，感觉这次收获了很多，特别是在一些案例题的时候，可以有一定思路的说出自己的想法了。&lt;br /&gt;
 怎么去界定自己这一步完成了呢？我是在这一步开始之前，先定一个目标，拿到几家 offer 之后，觉得自己应该准备好了，就算是完成了。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;大胆去面试心仪的公司&lt;br /&gt;
 一旦自己觉得可以试试心仪公司的时候，马上结束不心仪公司的面试，去投心仪公司，不要犹豫。一是公司的hc肯定是有限度的，二是继续面不心仪的公司不会给你带来多大的帮助，反而会浪费你的精力和时间。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;拿到心仪公司的offer后，尝试下更高层次的公司&lt;br /&gt;
 因为你很难保证会一辈子呆在这家公司，更高层次的公司可能就是你的下个目标，试下他们的难度呗，反正又没有什么坏处。&lt;br /&gt;
 其实我这一步没有怎么做，但是我还是推荐大家如果有时间和精力，可以去试试。&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h1 id=&quot;三-面试经验&quot;&gt;三 面试经验&lt;/h1&gt;

&lt;p&gt;今年的面试，大概面了 10+ 家吧，大概总结下自己面试的一些经验。&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;一般公司面试大概有这么几轮，组长面、leader 面、总监面、交叉面、hr 面。不排除有些公司为了效率会减少一轮或者几轮。&lt;/li&gt;
  &lt;li&gt;一般情况下，前几轮面试的重点在于基础能力的掌握，后几轮可能偏向于一些架构设计和问题分析，有些公司可以从 hr 那里知道下一轮的面试官处于什么样的职位，我们可以针对性的准备一些知识。&lt;/li&gt;
  &lt;li&gt;自我介绍是很重要的一部分，要突出自己的优势，尽量把接下来的话题引导到你擅长的地方。&lt;/li&gt;
  &lt;li&gt;面试其实有很大的运气成分，跟面试官聊的愉快与否直接关系到能不能通过，所有我们也可以根据是不是聊的愉快来大概判断自己有没有通过，但是也有些面试官会故意问一些很深的题，来考验你，答不上来不代表你们聊的不愉快。&lt;/li&gt;
  &lt;li&gt;有些面试官会在最后问你有没有想问他的，一般这个时候我都会问日常工作中接触到的组织架构大概是什么样子，一方面了解下公司的规模和人员大概情况，另一方面根据面试官会不会详细的讲解来判断自己的表现。&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;四-最后总结&quot;&gt;四 最后总结&lt;/h1&gt;

&lt;p&gt;找工作本身就是一个双向选择的事情，面试失败不代表你不优秀，可能只是你跟面试官脾气不合，这种情况就算进去，在日后的工作中也会很憋屈。况且大多数公司不同业务线和部门之间的招聘是不会冲突的，就算一个部门的面试失败，也不会妨碍你继续面试下一个部门。你要做的就是从失败的郁闷里面走出来，整理整理心情，继续出发。&lt;/p&gt;</content><author><name>sunbufu</name></author><category term="life" /><summary type="html">一 背景介绍</summary></entry><entry><title type="html">关于索引失效</title><link href="https://sunbufu.github.io/2019/12/26/mysql-unused-index/" rel="alternate" type="text/html" title="关于索引失效" /><published>2019-12-26T00:00:00+08:00</published><updated>2019-12-26T00:00:00+08:00</updated><id>https://sunbufu.github.io/2019/12/26/mysql-unused-index</id><content type="html" xml:base="https://sunbufu.github.io/2019/12/26/mysql-unused-index/">&lt;h1 id=&quot;1-使用-explain&quot;&gt;1. 使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EXPLAIN&lt;/code&gt;&lt;/h1&gt;
&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EXPLAIN&lt;/code&gt; 是很重要的一个 sql 关键字，可以帮我们查看 sql 的执行计划，寻找到 sql 的问题，优化你的 sql。 
使用起来却很简单，只需要在你原来的 sql 前面添加 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EXPLAIN&lt;/code&gt; 即可，但是我们的重点是在分析执行计划上。&lt;/p&gt;
&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;EXPLAIN&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t_order&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;执行计划各列的含义如下：详情请参考&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/explain-output.html&quot;&gt;官方文档&lt;/a&gt;&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;列名&lt;/th&gt;
      &lt;th&gt;含义&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;id&lt;/td&gt;
      &lt;td&gt;执行序号，mysql 会按照从大到小的顺序执行&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;select_type&lt;/td&gt;
      &lt;td&gt;查询类型：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SIMPLE&lt;/code&gt; 简单查询，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PRIMARY&lt;/code&gt; 外层查询，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SUBQUERY&lt;/code&gt; 子查询，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DERIVED&lt;/code&gt; 派生查询（FROM 中包含的子查询），&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UNION&lt;/code&gt; UNION 中第二个或后面的那个查询，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UNION RESULT&lt;/code&gt; UNION 的结果&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;table&lt;/td&gt;
      &lt;td&gt;引用的表&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;partitions&lt;/td&gt;
      &lt;td&gt;所属分区&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;type&lt;/td&gt;
      &lt;td&gt;访问类型&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/explain-output.html#explain-join-types&quot;&gt;官方文档&lt;/a&gt;，常见访问类型：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;system&lt;/code&gt; 只有一条记录的表（=系统表），&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;const&lt;/code&gt; 通过索引一次就查询到，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eq_ref&lt;/code&gt; 唯一索引等值扫描，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ref&lt;/code&gt; 非唯一索引等值扫描，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;range&lt;/code&gt; 范围索引扫描，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;index&lt;/code&gt; 索引扫描，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;all&lt;/code&gt; 全表扫描&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;possible_keys&lt;/td&gt;
      &lt;td&gt;可能使用的索引（优化前）&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;key&lt;/td&gt;
      &lt;td&gt;实际使用的索引（优化后）&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;key_len&lt;/td&gt;
      &lt;td&gt;使用索引的长度&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ref&lt;/td&gt;
      &lt;td&gt;上述表的连接匹配条件（哪些列或常量被用于查找索引列上的值）&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;rows&lt;/td&gt;
      &lt;td&gt;必须扫描的行数&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Extra&lt;/td&gt;
      &lt;td&gt;附加信息&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/explain-output.html#explain-extra-information&quot;&gt;官方文档&lt;/a&gt;，常见附加信息：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Using filesort&lt;/code&gt; mysql 无法利用索引完成排序操作，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Using temporary&lt;/code&gt; 使用了临时表保存中间结果，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Using index&lt;/code&gt; select 操作使用了覆盖索引，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Using where&lt;/code&gt; 使用 where 过滤，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;using join buffer&lt;/code&gt; 使用了连接缓存，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;impossible where&lt;/code&gt; where子句的值总是false，不能用来获取任何记录，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;distinct&lt;/code&gt; 优化 distinct，在找到第一个匹配的记录后停止扫描同样值的动作&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h1 id=&quot;2-索引失效&quot;&gt;2. 索引失效&lt;/h1&gt;

&lt;p&gt;索引失效是指，虽然建立了索引，查询中也使用了索引做条件，但是最后执行的时候却没有使用索引的情况。&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OR&lt;/code&gt; 关联非索引列&lt;/li&gt;
  &lt;li&gt;隐式类型转换&lt;br /&gt;
假设我们有个 varchar 类型 order_id 的索引。&lt;br /&gt;
反例：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SELECT * FROM order WHERE order_id = 123;&lt;/code&gt;&lt;br /&gt;
正例：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SELECT * FROM order WHERE order_id = '123';&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;运算符的使用&lt;br /&gt;
假设我们有个 int 类型 order_id 的索引。&lt;br /&gt;
反例：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SELECT * FROM order WHERE order_id - 1 = 9;&lt;/code&gt;&lt;br /&gt;
正例：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SELECT * FROM order WHERE order_id = 10;&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;函数的使用&lt;br /&gt;
假设我们有个 int 类型 order_id 的索引。&lt;br /&gt;
反例：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SELECT * FROM order WHERE ABS(order_id) = 9;&lt;/code&gt;&lt;br /&gt;
正例：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SELECT * FROM order WHERE order_id = 9;&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LIKE&lt;/code&gt; 以 % 开头&lt;br /&gt;
假设我们有个 varchar 类型的 user_name 的索引。&lt;br /&gt;
反例：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SELECT * FROM order WHERE user_name LIKE '%三';&lt;/code&gt;&lt;br /&gt;
正例：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SELECT * FROM order WHERE user_name LIKE '张%';&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;联合索引，未使用最左侧索引&lt;br /&gt;
假设我们有个联合索引 a,b,c，那么我们其实有 a，ab，abc。如果不使用 ‘最左前缀’ 的话，无法使用复合索引。&lt;br /&gt;
反例：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SELECT * FROM order WHERE b = 1;&lt;/code&gt;&lt;br /&gt;
正例：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SELECT * FROM order WHERE a = 1 AND b = 1;&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;mysql 觉得全表扫描更快(表数据少)&lt;/li&gt;
&lt;/ol&gt;

&lt;h1 id=&quot;3-总结&quot;&gt;3. 总结&lt;/h1&gt;

&lt;p&gt;索引在数据库的查询中，是很重要的点，合理的设置和使用索引，可以大大提升系统的响应速度。
索引失效又是索引使用过程中需要躲避的一个大坑，特此记录，以备查用。&lt;/p&gt;</content><author><name>sunbufu</name></author><category term="sql" /><summary type="html">1. 使用 EXPLAIN EXPLAIN 是很重要的一个 sql 关键字，可以帮我们查看 sql 的执行计划，寻找到 sql 的问题，优化你的 sql。 使用起来却很简单，只需要在你原来的 sql 前面添加 EXPLAIN 即可，但是我们的重点是在分析执行计划上。 EXPLAIN SELECT * FROM t_order; 执行计划各列的含义如下：详情请参考官方文档</summary></entry><entry><title type="html">状态模式的实现</title><link href="https://sunbufu.github.io/2019/08/16/state-pattern/" rel="alternate" type="text/html" title="状态模式的实现" /><published>2019-08-16T00:00:00+08:00</published><updated>2019-08-16T00:00:00+08:00</updated><id>https://sunbufu.github.io/2019/08/16/state-pattern</id><content type="html" xml:base="https://sunbufu.github.io/2019/08/16/state-pattern/">&lt;h1 id=&quot;一写在前面&quot;&gt;一、写在前面&lt;/h1&gt;
&lt;p&gt;之前有介绍过状态模式，但是不是特别直接。后来写了一篇 &lt;a href=&quot;https://sunbufu.github.io/2018/06/13/spring-statemachine/&quot;&gt;Spring StateMachine 介绍&lt;/a&gt;，有几位同学联系我说想要源码。但是其实我觉得如果不是逻辑特别复杂的话，我不是特别推荐使用状态机。因为我们完全可以通过状态模式来实现，而且更加灵活和简单。&lt;/p&gt;

&lt;h1 id=&quot;二状态模式&quot;&gt;二、状态模式&lt;/h1&gt;
&lt;p&gt;状态模式的定义此处不在赘述，有兴趣的同学可以看下&lt;a href=&quot;https://sunbufu.github.io/2018/06/06/design-patterns-04/#20%E7%8A%B6%E6%80%81%E6%A8%A1%E5%BC%8Fstate&quot;&gt;之前的文章&lt;/a&gt;。&lt;br /&gt;
首先，我们来定义几个名词。&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;状态（state）&lt;br /&gt;
这个比较好理解，状态模式嘛，就是管理状态的变更，所以首先我们要定义状态。&lt;/li&gt;
  &lt;li&gt;事件（event）&lt;br /&gt;
所谓事件，就是指状态变化的原因。例如，订单在经过支付事件之后，由 “待支付” 状态变为了 “待发货” 状态。&lt;/li&gt;
  &lt;li&gt;上下文（context）&lt;br /&gt;
负责状态以及状态的变更。&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;三示例&quot;&gt;三、示例&lt;/h1&gt;
&lt;p&gt;为了跟 spring 的 state-machine 对比，我们依然使用简单订单状态的例子。&lt;br /&gt;
&lt;img src=&quot;https://sunbufu.github.io/images/2019/08/16/state-pattern//20180507125704883.jpg&quot; alt=&quot;订单状态流程&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;31-状态state&quot;&gt;3.1 状态（state）&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://sunbufu.github.io/images/2019/08/16/state-pattern//orderstate.png&quot; alt=&quot;订单的状态定义&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cm&quot;&gt;/**
 * 订单状态
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OrderState&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;cm&quot;&gt;/**
     * 处理订单事件
     * @param orderStateContext  上下文
     * @param orderEvent    事件
     */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;handle&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;OrderStateContext&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;orderStateContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OrderEvent&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;orderEvent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;){&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;can not handle this event &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;orderEvent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cm&quot;&gt;/**
 * 订单待支付状态
 *
 * @author sunbufu
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;WaitPayState&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OrderState&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;handle&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;OrderStateContext&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;orderStateContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OrderEvent&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;orderEvent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;OrderEvent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;PAYED&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;orderEvent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;pay...&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;orderStateContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setOrderState&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;WaitDeliveryState&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;WaitPayState can not handle &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;orderEvent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cm&quot;&gt;/**
 * 订单待发货状态
 *
 * @author sunbufu
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;WaitDeliveryState&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OrderState&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;handle&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;OrderStateContext&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;orderStateContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OrderEvent&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;orderEvent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;OrderEvent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;DELIVERY&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;orderEvent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;delivery...&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;orderStateContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setOrderState&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;WaitReceiveState&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;WaitDeliveryState can not handle &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;orderEvent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cm&quot;&gt;/**
 * 订单待收货状态
 *
 * @author sunbufu
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;WaitReceiveState&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OrderState&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;handle&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;OrderStateContext&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;orderStateContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OrderEvent&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;orderEvent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;OrderEvent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;RECEIVED&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;orderEvent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;receive...&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;orderStateContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setOrderState&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;FinishState&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;WaitReceiveState can not handle &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;orderEvent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cm&quot;&gt;/**
 * 订单完结状态
 *
 * @author sunbufu
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;FinishState&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OrderState&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;handle&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;OrderStateContext&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;orderStateContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OrderEvent&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;orderEvent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;FinishState can not handle &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;orderEvent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;32-事件event&quot;&gt;3.2 事件（event）&lt;/h2&gt;
&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cm&quot;&gt;/**
 * 订单事件
 * 
 * @author sunbufu
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OrderEvent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/** 支付 */&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;PAYED&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/** 发货 */&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;DELIVERY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/** 收货 */&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;RECEIVED&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;33-上下文context&quot;&gt;3.3 上下文（context）&lt;/h2&gt;
&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cm&quot;&gt;/**
 * 订单状态上下文
 * 
 * @author sunbufu 
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OrderStateContext&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Order&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;order&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;cm&quot;&gt;/**
     * 修改订单状态
     *
     * @param orderState
     */&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;setOrderState&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;OrderState&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;orderState&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getOrder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getState&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot; --&amp;gt; &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;orderState&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;order&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;orderState&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;cm&quot;&gt;/**
     * 处理订单事件
     *
     * @param orderEvent
     */&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;handle&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;OrderEvent&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;orderEvent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;order&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getState&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;handle&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;orderEvent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;OrderStateContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;OrderStateContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Order&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;order&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;order&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;order&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Order&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getOrder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;order&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;setOrder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Order&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;order&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;order&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;order&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;34-测试&quot;&gt;3.4 测试&lt;/h2&gt;
&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Application&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;OrderStateContext&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;orderStateContext&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OrderStateContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Order&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;WaitPayState&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()));&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;orderStateContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;handle&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;OrderEvent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;PAYED&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;orderStateContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;handle&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;OrderEvent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;DELIVERY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;orderStateContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;handle&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;OrderEvent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;RECEIVED&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;四总结&quot;&gt;四、总结&lt;/h1&gt;
&lt;p&gt;我觉得，很多可以简单实现的功能，没必要引入庞大的框架，也许框架更容易实现你的功能，但是你在引入框架的同时，也让你的程序变得臃肿。所以这个度还需要开发者自己把握啊。&lt;/p&gt;</content><author><name>sunbufu</name></author><category term="design patterns" /><summary type="html">一、写在前面 之前有介绍过状态模式，但是不是特别直接。后来写了一篇 Spring StateMachine 介绍，有几位同学联系我说想要源码。但是其实我觉得如果不是逻辑特别复杂的话，我不是特别推荐使用状态机。因为我们完全可以通过状态模式来实现，而且更加灵活和简单。</summary></entry><entry><title type="html">青蛙与动态规划</title><link href="https://sunbufu.github.io/2019/06/11/frog-dynamic-programming/" rel="alternate" type="text/html" title="青蛙与动态规划" /><published>2019-06-11T00:00:00+08:00</published><updated>2019-06-11T00:00:00+08:00</updated><id>https://sunbufu.github.io/2019/06/11/frog-dynamic-programming</id><content type="html" xml:base="https://sunbufu.github.io/2019/06/11/frog-dynamic-programming/">&lt;h1 id=&quot;1-问题&quot;&gt;1. 问题&lt;/h1&gt;
&lt;p&gt;之前遇到过这么一个&lt;a href=&quot;https://leetcode-cn.com/problems/climbing-stairs/&quot; target=&quot;_blank&quot;&gt;问题&lt;/a&gt; ，说有一只青蛙，它想跳到 n 层的楼梯上面去，由于自身原因，它每次只能选择跳 1 层或者 2 层。&lt;br /&gt;
问，青蛙有多少种跳法？&lt;/p&gt;

&lt;p&gt;第一眼看到这个问题的时候有点蒙，不知道从何下手。不妨先从可见的楼梯层数 n 入手，设求青蛙跳法的方法是 f(n)。&lt;br /&gt;
那么当 n=1 时 f(n)=1, n=2 时 f(n)=2, n=3 时 f(n)=3, n=4 时 f(n)=5 … &lt;br /&gt;
很明显，f(n) 是一个斐波那锲数列的方法，当前数等于前两个数之和，所以有 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f(n)=f(n-1)+f(n-2)&lt;/code&gt;。&lt;br /&gt;
其实从另一个角度想也可以想明白，假设我是那只青蛙，站在 n 层的楼梯脚下，我有 f(n) 种跳法，现在我能选择的是跳 1 层还是跳 2 层。当我选择跳 1 层时，我接下来的跳法还有 f(n-1) 种；当我选择跳 2 层时，我接下来的跳法还有 f(n-2) 种。所以我在还没有选择之前的跳法应该等于我这两种跳法之和，所以有 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f(n)=f(n-1)+f(n-2)&lt;/code&gt;。&lt;/p&gt;

&lt;h1 id=&quot;2-解答&quot;&gt;2. 解答&lt;/h1&gt;

&lt;h2 id=&quot;21-递归&quot;&gt;2.1 递归&lt;/h2&gt;
&lt;p&gt;上面的思路有了，我们很容易就可以用代码实现了。&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;climbStairs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; 
    &lt;span class=&quot;c1&quot;&gt;// f(n)=f(n-1)+f(n-2)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;climbStairs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;climbStairs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;上面的代码虽然可以解决问题，但是会出现很大一部分的重复运算。
如下图所示，当 n=6 时，我们计算了 2 次 f(4), 3 次 f(3)。
&lt;img src=&quot;https://sunbufu.github.io/images/2019/06/11/frog-dynamic-programming//f6.jpg&quot; alt=&quot;f(6)&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;22-备忘录模式&quot;&gt;2.2 备忘录模式&lt;/h2&gt;
&lt;p&gt;基于上面的问题，我们可以使用备忘录模式，维护一个 map ，key 表示台阶层数 n，value 表示跳法。把计算过的结果放在 map 中，在开始计算之前先检查下备忘录 map 中是否已经有对应的结果了，如果没有再计算，并把计算完成后的结果添加到备忘录 map 中。&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nc&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Integer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Integer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;memoMap&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;HashMap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;gt;();&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;climbStairs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// 检查备忘录中是否已经存在相应结果&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;memoMap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;containsKey&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;memoMap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;climbStairs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;climbStairs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// 计算完成之后把结果添加到备忘录中&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;memoMap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;put&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;23-迭代&quot;&gt;2.3 迭代&lt;/h2&gt;
&lt;p&gt;我们知道，递归可以优化成迭代，我们该如何做呢？&lt;br /&gt;
递归可以理解为是自上而下的解决问题，不断的把问题分解成一个个的小问题，直到得到这一个个的小问题答案后，再汇集成整个问题的答案。 &lt;br /&gt;
迭代可以理解为是自下而上的解决问题，不断的累计一个个的小问题的答案，直到累计得到大问题的答案。&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;climbStairs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// 定义数组记录下标为 n 对应的跳法&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resultArray&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;resultArray&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;resultArray&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;resultArray&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resultArray&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resultArray&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resultArray&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;3-总结&quot;&gt;3. 总结&lt;/h1&gt;

&lt;h2 id=&quot;31-动态规划的定义&quot;&gt;3.1 动态规划的定义&lt;/h2&gt;
&lt;p&gt;什么是动态规划，我在 &lt;a href=&quot;https://zh.wikipedia.org/wiki/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92&quot; target=&quot;_blank&quot;&gt;维基百科&lt;/a&gt; 查到的定义如下。&lt;br /&gt;
动态规划（英语：Dynamic programming，简称 DP）是一种在数学、管理科学、计算机科学、经济学和生物信息学中使用的，通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。&lt;/p&gt;

&lt;h2 id=&quot;32-适用情况&quot;&gt;3.2 适用情况&lt;/h2&gt;
&lt;ol&gt;
  &lt;li&gt;最优子结构性质。如果问题的最优解所包含的子问题的解也是最优的，我们就称该问题具有最优子结构性质（即满足最优化原理）。最优子结构性质为动态规划算法解决问题提供了重要线索。&lt;/li&gt;
  &lt;li&gt;无后效性。即子问题的解一旦确定，就不再改变，不受在这之后、包含它的更大的问题的求解决策影响。&lt;/li&gt;
  &lt;li&gt;子问题重叠性质。子问题重叠性质是指在用递归算法自顶向下对问题进行求解时，每次产生的子问题并不总是新问题，有些子问题会被重复计算多次。动态规划算法正是利用了这种子问题的重叠性质，对每一个子问题只计算一次，然后将其计算结果保存在一个表格中，当再次需要计算已经计算过的子问题时，只是在表格中简单地查看一下结果，从而获得较高的效率。&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;32-解法步骤&quot;&gt;3.2 解法步骤&lt;/h2&gt;
&lt;ol&gt;
  &lt;li&gt;描述最优解的结构特征&lt;/li&gt;
  &lt;li&gt;递归地定义一个最优解的值&lt;/li&gt;
  &lt;li&gt;自底向上计算一个最优解的值&lt;/li&gt;
  &lt;li&gt;从已计算的信息中构造一个最优解&lt;/li&gt;
&lt;/ol&gt;</content><author><name>sunbufu</name></author><category term="algorithm" /><summary type="html">1. 问题 之前遇到过这么一个问题 ，说有一只青蛙，它想跳到 n 层的楼梯上面去，由于自身原因，它每次只能选择跳 1 层或者 2 层。 问，青蛙有多少种跳法？</summary></entry><entry><title type="html">关于生活的一点思考</title><link href="https://sunbufu.github.io/2019/05/10/about-life/" rel="alternate" type="text/html" title="关于生活的一点思考" /><published>2019-05-10T00:00:00+08:00</published><updated>2019-05-10T00:00:00+08:00</updated><id>https://sunbufu.github.io/2019/05/10/about-life</id><content type="html" xml:base="https://sunbufu.github.io/2019/05/10/about-life/">&lt;h1 id=&quot;1关于婚姻&quot;&gt;1.关于婚姻&lt;/h1&gt;
&lt;p&gt;2019-03-17 我们在家里举行了婚礼，婚礼还算是隆重。同学、朋友、亲戚和乡里乡亲来的不少，也搞得热热闹闹的，挺开心。当天下午婚礼完成后，粘床就睡着了，有点累也有点满足，我想我们完成了对彼此的承诺。换回正常的衣服，第二天去了我姥姥家，下午又回了门。其实我之前并不喜欢这些仪式，觉得是一种华而不实的繁文缛节而已。但是亲身经历过后改变了我的一些想法，生活是需要仪式感的，真的需要。&lt;/p&gt;

&lt;p&gt;后来我们又去到巴黎岛度蜜月，一块同行的也是几对刚刚完婚的新人。到巴里已是半夜，刚下飞机，迎面而来的是热带的气流混杂着焚香的气息。我们报的是七天的旅行团，导游和司机拉着我们到处兜兜转转。留给我印象最深的不是民族风情和无边泳池，更不是五星酒店和悬崖秋千，而是蓝梦岛湛蓝的海水和金巴兰舒缓的落日。我在国内也偶尔去看海，青岛的金沙滩和日照的万平口都是那种淡蓝色的海水冲刷着土黄色的沙滩。而蓝梦岛的海水是真的蓝啊，甚至蓝到以为是一场梦，我想这也许是”蓝梦岛”名称的由来吧。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://sunbufu.github.io/images/2019/05/10/about-life//lembongan.jpg&quot; alt=&quot;蓝梦岛的海水&quot; /&gt;
&lt;img src=&quot;https://sunbufu.github.io/images/2019/05/10/about-life//jimbaran.jpg&quot; alt=&quot;京巴兰的落日&quot; /&gt;&lt;/p&gt;

&lt;p&gt;从巴厘岛回来后，我们的婚假也休完了。又要投入到繁忙的工作和生活中去了，但是我的心情却多了一些小欢愉，我想这就是我对待婚姻对待她的态度吧。&lt;/p&gt;

&lt;h1 id=&quot;2关于人生&quot;&gt;2.关于人生&lt;/h1&gt;
&lt;p&gt;我们的人生很长，我们有很多目标和理想，也有很多经验和教训。”人生”是一个很大的标题，大到让我们可以聊上三天三夜。有时我会去想，当我们谈论”人生”的时候，我们到底在谈论什么？换个角度来分析这个标题，我们可以把”人生”拆分成很多个的”昨天”、”今天”和”明天”。&lt;/p&gt;

&lt;p&gt;“昨天”是已经过去的人生，留给我们的是经验和教训。它是无奈的，因为不管你犯了什么错，多么的悔恨，都无法改变既定的事实。但同时它又是宝贵的，一个人的价值不正是通过他的经验来体现的吗。”明天”是还没有到来人生，我们做的是在它到来之前，结合”昨天”的经验来制定正确的计划。而只有”今天”是我们唯一可以把握的，我们可以无视”昨天”的教训，不管”明天”的计划，洒洒脱脱的浪费”今天”。也可以总结”昨天”的教训，制定”明天”的计划，完完整整的过完充实一天。但是不管怎么做，”今天”终究会变成”昨天”，”明天”也会成为”今天”，而新的”明天”也会缓缓的无法阻挡的到来。&lt;/p&gt;

&lt;p&gt;但是从另一方面来讲，对于我们那些很远大的计划来说，我们也不是无计可施了。不用去理会那些流言蜚语，也不去管目标有多么的宏图远大，只需要做好”昨天”的总结、”明天”的计划，一步一步的走完”今天”，无怨无悔就够了。&lt;/p&gt;</content><author><name>sunbufu</name></author><category term="life" /><summary type="html">1.关于婚姻 2019-03-17 我们在家里举行了婚礼，婚礼还算是隆重。同学、朋友、亲戚和乡里乡亲来的不少，也搞得热热闹闹的，挺开心。当天下午婚礼完成后，粘床就睡着了，有点累也有点满足，我想我们完成了对彼此的承诺。换回正常的衣服，第二天去了我姥姥家，下午又回了门。其实我之前并不喜欢这些仪式，觉得是一种华而不实的繁文缛节而已。但是亲身经历过后改变了我的一些想法，生活是需要仪式感的，真的需要。</summary></entry><entry><title type="html">2018 年终总结</title><link href="https://sunbufu.github.io/2019/01/26/annual-summary/" rel="alternate" type="text/html" title="2018 年终总结" /><published>2019-01-26T00:00:00+08:00</published><updated>2019-01-26T00:00:00+08:00</updated><id>https://sunbufu.github.io/2019/01/26/annual-summary</id><content type="html" xml:base="https://sunbufu.github.io/2019/01/26/annual-summary/">&lt;p&gt;今天是 2019-01-26，等明天过完就是放假的日子了，今天坐 9 点的班车到公司，空空荡荡的，借此机会总结下我的 2018 吧。&lt;/p&gt;

&lt;h1 id=&quot;2018-年记忆深刻的事情&quot;&gt;2018 年记忆深刻的事情&lt;/h1&gt;

&lt;h2 id=&quot;1换工作&quot;&gt;1.换工作&lt;/h2&gt;
&lt;p&gt;3 月份水上德州因为政策原因不再经营，我也换了工作来到瓜子，从事供应链开发相关。
这次找工作给我带来的感触颇多，总结下。&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;面试题要多刷。很多知识在平时的工作中可能会用不到，但并不代表你可以不了解，等遇到的时候至少要有一个思路吧。这也就是有人说的’面试造火箭，工作拧螺丝’，但是事实就是这么个理。&lt;/li&gt;
  &lt;li&gt;基础肯定要都复习一遍。下层基础决定上层建筑嘛，差距除了表面上的框架使用经验，最大的还是在基础，这也是判断一个人能否深入了解和研究的依据吧。&lt;/li&gt;
  &lt;li&gt;尽量不要去小公司了吧。不是说小公司不好，而是很多东西是小公司学不到，也没有机会让你去学的，反而装系统、装软件等很多繁琐的小事回去占据你的时间。还有一点，小公司的工作经验可能没有大公司的值钱，你的简历上肯定会写上家公司，’某某公司前员工’可能会成为面试官给你的第一个标签。小公司可能经不太起风浪，前家公司到现在也没有跟我结清工资。&lt;/li&gt;
  &lt;li&gt;筛选公司去面试。boss、拉钩什么的软件都用起来，猎头、内推也搞起来。但是也不要海投了吧，精力不允许啊，适当的筛选下。&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;2买房子&quot;&gt;2.买房子&lt;/h2&gt;
&lt;p&gt;5 月份的时候去青岛看了下房子，其实在 17 年的时候我就有来看过。伏董租了辆车，带我逛了逛各个售楼处。出于多个方向的考虑，最后在城阳买了房子。然后接下来的一段时间，经常往青岛跑，什么网签、办贷款、拿合同，最后还好都顺利搞定了。9 月份的时候顺利办理了公积金的提取，一切顺利。&lt;/p&gt;

&lt;h2 id=&quot;3结婚证&quot;&gt;3.结婚证&lt;/h2&gt;
&lt;p&gt;12 月份，去了趟青岛。终于跟孙彩云把证给领了，我们恋爱了 5 年，不长也不短，感觉怎么说呢，很幸运😄。&lt;/p&gt;

&lt;h1 id=&quot;2018-年没做的事情&quot;&gt;2018 年没做的事情&lt;/h1&gt;
&lt;h2 id=&quot;1旅游&quot;&gt;1.旅游&lt;/h2&gt;
&lt;p&gt;答应带孙彩云去旅旅游，散散心。最后也没来得及做，公司的事情有点忙。&lt;/p&gt;
&lt;h2 id=&quot;2技术&quot;&gt;2.技术&lt;/h2&gt;
&lt;p&gt;怎么说呢，技术没有达到自己预期的那个高度吧。&lt;/p&gt;

&lt;h1 id=&quot;2019-年要去做的事情&quot;&gt;2019 年要去做的事情&lt;/h1&gt;
&lt;h2 id=&quot;1结婚&quot;&gt;1.结婚&lt;/h2&gt;
&lt;p&gt;婚礼已经定了，过年回家的时候再把详细的事情看下。&lt;/p&gt;
&lt;h2 id=&quot;2旅游&quot;&gt;2.旅游&lt;/h2&gt;
&lt;p&gt;肯定要带孙彩云出去耍耍了，不能再拖了。不能让自己一直处于一个工作，吃饭，睡觉的循环里面。人毕竟不是机器吗，偶尔懈怠下，放松一下也未尝不可了。&lt;/p&gt;
&lt;h2 id=&quot;3技术&quot;&gt;3.技术&lt;/h2&gt;
&lt;p&gt;技术是无止境的，&lt;a href=&quot;https://leetcode-cn.com&quot; target=&quot;_blank&quot;&gt;刷刷题&lt;/a&gt;吧。&lt;/p&gt;</content><author><name>sunbufu</name></author><category term="experience" /><category term="life" /><summary type="html">今天是 2019-01-26，等明天过完就是放假的日子了，今天坐 9 点的班车到公司，空空荡荡的，借此机会总结下我的 2018 吧。</summary></entry><entry><title type="html">单例模式的实现</title><link href="https://sunbufu.github.io/2019/01/26/singleton/" rel="alternate" type="text/html" title="单例模式的实现" /><published>2019-01-26T00:00:00+08:00</published><updated>2019-01-26T00:00:00+08:00</updated><id>https://sunbufu.github.io/2019/01/26/singleton</id><content type="html" xml:base="https://sunbufu.github.io/2019/01/26/singleton/">&lt;h1 id=&quot;一定义&quot;&gt;一、定义&lt;/h1&gt;
&lt;p&gt;单例模式，是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中，应用该模式的一个类只有一个实例。即一个类只有一个对象实例。  &lt;br /&gt;
详情可以参考之前的博客 &lt;a href=&quot;https://sunbufu.github.io/2018/06/06/design-patterns-01/#3单例模式singleton&quot; target=&quot;_blank&quot;&gt;单例模式&lt;/a&gt;。&lt;/p&gt;
&lt;h1 id=&quot;二实现&quot;&gt;二、实现&lt;/h1&gt;
&lt;h2 id=&quot;21-基本实现&quot;&gt;2.1 基本实现&lt;/h2&gt;
&lt;p&gt;单例模式可以笼统的分为 饿汉式 和 懒汉式。&lt;/p&gt;
&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// 饿汉式&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Singleton&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/** 私有的构造方法 */&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Singleton&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/** 私有的静态的对象 */&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Singleton&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;singleton&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Singleton&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/** 公共的静态的获取对象的方法 */&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Singleton&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getInstance&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(){&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;singleton&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// 懒汉式&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Singleton&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* 持有私有静态实例，防止被引用，此处赋值为null，目的是实现延迟加载 */&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Singleton&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* 私有构造方法，防止被实例化 */&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Singleton&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* 静态工程方法，创建实例 */&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Singleton&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getInstance&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Singleton&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* 如果该对象被用于序列化，可以保证对象在序列化前后保持一致 */&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Object&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;readResolve&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;饿汉式 会在类加载时直接创建对象。懒汉式 有点类似懒加载的感觉，在第一次使用的时候创建对象，但是这样也带来一个问题，如何保证线程安全。
上面的 懒汉式 其实是有问题的，多线程同时调用的时候会创建多个实例，所以用的比较多的是 double check 的实现方式。&lt;/p&gt;
&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// double check&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Singleton&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* 持有私有静态实例，防止被引用，此处赋值为null，目的是实现延迟加载 */&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Singleton&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;cm&quot;&gt;/* 私有构造方法，防止被实例化 */&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Singleton&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    
    &lt;span class=&quot;cm&quot;&gt;/* 静态工程方法，创建实例 */&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Singleton&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getInstance&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;kd&quot;&gt;synchronized&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Singleton&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Singleton&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    
    &lt;span class=&quot;cm&quot;&gt;/* 如果该对象被用于序列化，可以保证对象在序列化前后保持一致 */&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Object&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;readResolve&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;这样就能保证线程安全，保障只有一个实例最后会被创建。但还有一个问题，JVM 可能会在执行的时候进行指令重排序，
因为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;instance = new Singleton();&lt;/code&gt; 这条语句并不是一个原子性操作，实际上是执行了三件事情。&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;给 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Singleton&lt;/code&gt; 分配空间&lt;/li&gt;
  &lt;li&gt;调用构造方法，实例化&lt;/li&gt;
  &lt;li&gt;将 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;instance&lt;/code&gt; 指向 1 中分配的空间&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;只要第 3 步执行完成，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;instance&lt;/code&gt; 就已经不是 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;null&lt;/code&gt;。但是 JVM 可能会进行指令重排序，2 和 3 的先后顺序是不确定的。&lt;br /&gt;
如果 JVM 是按照 132 执行的，且恰好有多个线程在竞争的时候，那么可能会出现 第一个线程在执行到 3 的时候被暂停，第二个线程开始执行，执行到 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if (instan == null)&lt;/code&gt; 的判断时，直接拿 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;instance&lt;/code&gt; 出去使用了，但是当前的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;instance&lt;/code&gt; 并没有实例化完成，也就会出现问题。&lt;br /&gt;
解决方案可以给 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;instance&lt;/code&gt; 添加 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;volatile&lt;/code&gt; 关键字。实现如下所示：&lt;/p&gt;
&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Singleton&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* 持有私有静态实例，防止被引用，此处赋值为null，目的是实现延迟加载 */&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;volatile&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Singleton&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* 私有构造方法，防止被实例化 */&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Singleton&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* 静态工程方法，创建实例 */&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Singleton&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getInstance&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;kd&quot;&gt;synchronized&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Singleton&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;){&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;){&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Singleton&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/* 如果该对象被用于序列化，可以保证对象在序列化前后保持一致 */&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Object&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;readResolve&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;volatile&lt;/code&gt; 表示所有的对所修饰变量的操作，都不会被拷贝到线程缓存中执行。阻止 JVM 的指令重排序，要求按照 123 的顺序来执行。&lt;/p&gt;

&lt;h2 id=&quot;22-其他实现&quot;&gt;2.2 其他实现&lt;/h2&gt;
&lt;p&gt;这样看起来，就越来越繁琐了，本来就是想实现一个简单、高效的单例模式，一点一点的增加了很多代码。所以有人提出了下面的两种实现方式。&lt;/p&gt;

&lt;h3 id=&quot;221-静态内部类&quot;&gt;2.2.1 静态内部类&lt;/h3&gt;
&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Singleton&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Singleton&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Singleton&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getInstance&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SingletonHolder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;INSTANCE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SingletonHolder&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Singleton&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;INSTANCE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Singleton&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;采用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SingletonHolder&lt;/code&gt; 的方式，使用静态内部类保证类只会被实例化一次，同时又会在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getInstance()&lt;/code&gt; 第一次调用的时候被实例化。&lt;/p&gt;

&lt;h3 id=&quot;222-枚举&quot;&gt;2.2.2 枚举&lt;/h3&gt;
&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Singleton&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Singleton&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Singleton&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getInstance&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SingletonHolder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;INSTANCE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getSingleton&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SingletonHolder&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;no&quot;&gt;INSTANCE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Singleton&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;singleton&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;SingletonHolder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;singleton&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Singleton&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Singleton&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getSingleton&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;singleton&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;采用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SingletonHolder&lt;/code&gt; 的方式，使用枚举。因为枚举会由 JVM 保证只会实例化一次，所以肯定是线程安全的。&lt;br /&gt;
当前，你也可以直接用枚举来做单例，直接写方法到枚举中。&lt;/p&gt;
&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Singleton&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;INSTANCE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;func1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(){&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// do some thing.&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;三总结&quot;&gt;三、总结&lt;/h1&gt;
&lt;p&gt;最后，推荐借助枚举的实现方式，枚举的实现方式已经成为单例模式的最佳实践。前一段时间看到 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RestTemaple&lt;/code&gt; 的实现的时候，有看到在执行 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;URLEncode&lt;/code&gt; 的时，各种字符便是保存在枚举实现的单例模式中。&lt;/p&gt;</content><author><name>sunbufu</name></author><category term="design patterns" /><summary type="html">一、定义 单例模式，是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中，应用该模式的一个类只有一个实例。即一个类只有一个对象实例。 详情可以参考之前的博客 单例模式。 二、实现 2.1 基本实现 单例模式可以笼统的分为 饿汉式 和 懒汉式。 // 饿汉式 public class Singleton { /** 私有的构造方法 */ private Singleton() { } /** 私有的静态的对象 */ private static Singleton singleton = new Singleton(); /** 公共的静态的获取对象的方法 */ public static Singleton getInstance(){ return singleton; } } // 懒汉式 public class Singleton { /* 持有私有静态实例，防止被引用，此处赋值为null，目的是实现延迟加载 */ private static Singleton instance = null; /* 私有构造方法，防止被实例化 */ private Singleton() { } /* 静态工程方法，创建实例 */ public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } /* 如果该对象被用于序列化，可以保证对象在序列化前后保持一致 */ public Object readResolve() { return instance; } } 饿汉式 会在类加载时直接创建对象。懒汉式 有点类似懒加载的感觉，在第一次使用的时候创建对象，但是这样也带来一个问题，如何保证线程安全。 上面的 懒汉式 其实是有问题的，多线程同时调用的时候会创建多个实例，所以用的比较多的是 double check 的实现方式。 // double check public class Singleton { /* 持有私有静态实例，防止被引用，此处赋值为null，目的是实现延迟加载 */ private static Singleton instance = null; /* 私有构造方法，防止被实例化 */ private Singleton() { } /* 静态工程方法，创建实例 */ public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } /* 如果该对象被用于序列化，可以保证对象在序列化前后保持一致 */ public Object readResolve() { return instance; } } 这样就能保证线程安全，保障只有一个实例最后会被创建。但还有一个问题，JVM 可能会在执行的时候进行指令重排序， 因为 instance = new Singleton(); 这条语句并不是一个原子性操作，实际上是执行了三件事情。 给 Singleton 分配空间 调用构造方法，实例化 将 instance 指向 1 中分配的空间</summary></entry><entry><title type="html">常见缓存淘汰算法</title><link href="https://sunbufu.github.io/2019/01/26/cache-eviction/" rel="alternate" type="text/html" title="常见缓存淘汰算法" /><published>2019-01-26T00:00:00+08:00</published><updated>2019-01-26T00:00:00+08:00</updated><id>https://sunbufu.github.io/2019/01/26/cache-eviction</id><content type="html" xml:base="https://sunbufu.github.io/2019/01/26/cache-eviction/">&lt;h1 id=&quot;一缓存&quot;&gt;一、缓存&lt;/h1&gt;
&lt;p&gt;缓存（Cache） 一词来源于 1967 年的一篇电子工程期刊论文。其作者将法语词 “cache” 赋予 “safekeeping storage” 的涵义，用于计算机工程领域。&lt;br /&gt;
最早是因为 CPU 与内存之间运算和读写速度不一致，在 CPU 添加一块空间用于提前将内存中数据加载进来，提高 整体的速度，这块空间被称为 缓存（Cache）。如今缓存的概念已被扩充，在内存和硬盘之间也有 Cache（磁盘缓存），乃至在硬盘与网络之间也有某种意义上的 Cache ──称为 Internet 临时文件夹或网络内容缓存等。凡是位于速度相差较大的两种硬件之间，用于协调两者数据传输速度差异的结构，均可称之为 Cache。&lt;br /&gt;
但是缓存的空间是宝贵的，所以我们不会将所有的数据都缓存起来，必须依赖一定的规则淘汰掉一部分数据。这个规则就是我们讨论的缓存淘汰算法。&lt;/p&gt;

&lt;h1 id=&quot;二缓存淘汰&quot;&gt;二、缓存淘汰&lt;/h1&gt;
&lt;h2 id=&quot;21-fifo先入先出&quot;&gt;2.1 FIFO（先入先出）&lt;/h2&gt;
&lt;p&gt;FIFO (First In FIrst Out) 是最简单的算法，原理跟名字一样，&lt;strong&gt;“如果一个数据最先进入缓存中，则应该最早淘汰掉”&lt;/strong&gt;。把缓存中的数据看成一个队列，最先加入的数据位于队列的头部，最后加入位于队列的尾部。当缓存空间不足需要执行缓存淘汰操作时，从队列的头部开始淘汰。
如下所示，假设我们的缓存可以缓存 3 对数据，1 加入时处于队列的头部，2 和 3 加入时缓存空间充足。当 4 加入时，执行缓存淘汰，由于 1 处于队列的头部，所以被淘汰。同理 5 加入时，2 被淘汰。&lt;br /&gt;
Java 中有单独的队列 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Queue&lt;/code&gt; ，可以使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LinkedList&lt;/code&gt;。&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;1&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;2&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;3&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;4&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;5&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;3=c&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;4=e&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;5=f&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;2=b&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;2=b&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;3=c&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;4=e&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;1=a&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;1=a&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;1=a&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;2=b&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;3=c&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id=&quot;22-lru最近最少被使用&quot;&gt;2.2 LRU（最近最少被使用）&lt;/h2&gt;
&lt;p&gt;LRU (Least Recently Used) 的核心思想是基于&lt;strong&gt;“如果数据最近被访问过，它在未来也极有可能访问过”&lt;/strong&gt;。同样把缓存看成一个队列，访问一个数据时，如果缓存中不存在，则插入到队列尾部；如果缓存中存在，则把该数据移动到队列尾部。当执行淘汰操作时，同样从队列的头部开始淘汰。
如下所示，1、2、3 加入时缓存空间充足，接下来 1 又被访问了一次，所以 1 被移动到队列尾部。当 4 加入时，执行缓存淘汰，2 位于队列头部被淘汰。
Java 中可以直接使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LinkedHashMap&lt;/code&gt; 来实现。&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;1&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;2&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;3&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;1&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;4&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;3=c&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;1=a&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;4=e&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;2=b&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;2=b&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;3=c&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;1=a&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;1=a&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;1=a&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;1=a&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;2=b&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;3=c&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id=&quot;23-lfu最不经常使用&quot;&gt;2.3 LFU（最不经常使用）&lt;/h2&gt;
&lt;p&gt;LFU （Least Frequently Used）的核心思想是&lt;strong&gt;“如果一个数据在最近一段时间内使用次数很少，那么在将来一段时间内被使用的可能性也很小”&lt;/strong&gt;，会记录数据访问的次数，当需要进行淘汰操作时，淘汰掉访问次数最少的数据。
如下所示，一开始 1 被连续访问了两次，接下来 2 被访问一次，3 被访问一次，按照访问次数排序，访问次数少的处于队列头部。当 4 加入时，执行缓存淘汰，2 位于队列头部被淘汰。&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;1&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;1&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;2&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;3&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;4&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;1=a (2)&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;1=a (2)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;1=a (2)&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;3=c (1)&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;4=e(1)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;1=a (1)&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;1=a (2)&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;2=b (1)&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;2=b (1)&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;3=c (1)&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id=&quot;24-其他&quot;&gt;2.4 其他&lt;/h2&gt;
&lt;p&gt;还有一些其他的淘汰算法：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;2Q（Two Queues）：同时采用 FIFO 和 LRU 两个队列，首次访问数据时加入到 FIFO 队列中，如果数据在 FIFO 队列移除之前被再次访问，数据会被移动到 LRU 队列中。&lt;/li&gt;
  &lt;li&gt;LRU-K ：是一种 LRU 算法的增强版，在 LRU 维护队列的基础上，再添加一个队列维护数据访问的次数，由原来访问 1 次会被添加到缓存中，改为访问 K 次才会被加入到缓存中。&lt;/li&gt;
  &lt;li&gt;ARC：在IBM Almaden研究中心开发，这个缓存算法同时跟踪记录LFU和LRU，以及驱逐缓存条目，来获得可用缓存的最佳使用。&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;三常见示例&quot;&gt;三、常见示例&lt;/h1&gt;
&lt;h2 id=&quot;31-ehcache-中的缓存淘汰&quot;&gt;3.1 Ehcache 中的缓存淘汰&lt;/h2&gt;
&lt;p&gt;Ehcache 提供了 3 种淘汰机制（驱逐策略），分别是 LRU（默认），LFU，FIFO。但是 Ehcache 的淘汰却不是给予全局的策略，执行步骤如下：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;判断是否超过最大容量限制&lt;/li&gt;
  &lt;li&gt;在缓存中随机取出不超过 30 个元素作为样本&lt;/li&gt;
  &lt;li&gt;根据淘汰策略确定需要淘汰的元素&lt;/li&gt;
  &lt;li&gt;在缓存中移除元素&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;32-redis-中的缓存淘汰&quot;&gt;3.2 redis 中的缓存淘汰&lt;/h2&gt;
&lt;p&gt;在 redis 中可以配置 6 中淘汰机制：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;noeviction：不删除策略, 达到最大内存限制时, 如果需要更多内存, 直接返回错误信息。&lt;/li&gt;
  &lt;li&gt;allkeys-lru：所有 key 通用，优先删除最近最少使用 (LRU) 的 key。&lt;/li&gt;
  &lt;li&gt;volatile-lru：只限于设置了 expire 的部分; 优先删除最近最少使用 (LRU) 的 key。&lt;/li&gt;
  &lt;li&gt;allkeys-random：所有 key 通用; 随机删除一部分 key。&lt;/li&gt;
  &lt;li&gt;volatile-random：只限于设置了 expire 的部分; 随机删除一部分 key。&lt;/li&gt;
  &lt;li&gt;volatile-ttl：只限于设置了 expire 的部分; 优先删除剩余时间 (time to live,TTL) 短的key。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;详细介绍可以参考 &lt;a href=&quot;https://redis.io/topics/lru-cache/&quot; target=&quot;_blank&quot;&gt;官方文档&lt;/a&gt; 。&lt;/p&gt;

&lt;h2 id=&quot;33-guava-中的缓存淘汰&quot;&gt;3.3 Guava 中的缓存淘汰&lt;/h2&gt;
&lt;p&gt;Guava 在维护缓存数据的同时，还维护了 WirteQueue 和 AccessQueue，分别用来记录写入的记录和访问的记录。总体来说有 4 种淘汰策略：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Size-base Eviction：基于使用量的淘汰策略。&lt;/li&gt;
  &lt;li&gt;Timed Eviction：基于时间驱逐，提供了根据访问时间（expireAfterAccess）和根据写入时间（expireAfterWrite）。&lt;/li&gt;
  &lt;li&gt;Reference-based Eviction：基于引用驱逐（通过 java 的软、弱引用实现）。&lt;/li&gt;
  &lt;li&gt;Explicit Removals：显示移除。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;详细介绍可以参考 &lt;a href=&quot;https://github.com/google/guava/wiki/CachesExplained&quot; target=&quot;_blank&quot;&gt;官方文档&lt;/a&gt;。&lt;/p&gt;</content><author><name>sunbufu</name></author><category term="algorithm" /><summary type="html">一、缓存 缓存（Cache） 一词来源于 1967 年的一篇电子工程期刊论文。其作者将法语词 “cache” 赋予 “safekeeping storage” 的涵义，用于计算机工程领域。 最早是因为 CPU 与内存之间运算和读写速度不一致，在 CPU 添加一块空间用于提前将内存中数据加载进来，提高 整体的速度，这块空间被称为 缓存（Cache）。如今缓存的概念已被扩充，在内存和硬盘之间也有 Cache（磁盘缓存），乃至在硬盘与网络之间也有某种意义上的 Cache ──称为 Internet 临时文件夹或网络内容缓存等。凡是位于速度相差较大的两种硬件之间，用于协调两者数据传输速度差异的结构，均可称之为 Cache。 但是缓存的空间是宝贵的，所以我们不会将所有的数据都缓存起来，必须依赖一定的规则淘汰掉一部分数据。这个规则就是我们讨论的缓存淘汰算法。</summary></entry></feed>