<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>GeekerIT</title>
        <link>https://blog.geekerit.com/</link>
        <description>简单的记录个人心得、生活感悟。</description>
        <lastBuildDate>Fri, 02 Aug 2024 10:32:36 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>zh-CN</language>
        <copyright>All rights reserved 2024, Run</copyright>
        <item>
            <title><![CDATA[Java定时任务那些事儿]]></title>
            <link>https://blog.geekerit.com/article/42bb4d90-1c2c-4865-a1b8-01eaa8610f72</link>
            <guid>https://blog.geekerit.com/article/42bb4d90-1c2c-4865-a1b8-01eaa8610f72</guid>
            <pubDate>Sun, 28 Jul 2024 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<div id="notion-article" class="mx-auto overflow-hidden "><main class="notion light-mode notion-page notion-block-42bb4d901c2c4865a1b801eaa8610f72"><div class="notion-viewport"></div><div class="notion-collection-page-properties"></div><div class="notion-sync-block notion-block-88fa2263585a43f4b758650d6a2a8eb4"><div class="notion-text notion-block-a73f689b91404ad093f55512616b0939">我们在项目开发可能会存在需要定时运行某类任务的场景，例如定时数据同步，定期发送营销短信等，如果这些定时运行的任务我们都通过新的线程不断轮询的方式实现的话，至少会存在以下问题：</div><ul class="notion-list notion-list-disc notion-block-fad6a60a46c144eb870d012b0caf465e"><li>每个定时运行的任务都需要创建新的线程来处理，线程资源无法管控；当定时任务被取消的时候线程生命周期结束，如果需要再次执行定时任务又需要再次创建线程，线程的创建销毁成本高。</li></ul><ul class="notion-list notion-list-disc notion-block-e36deebfb7a7497295e09d7f1feedf56"><li>执行定时任务的线程轮询周期需要手动处理，在业务开发过程中需要关注这些基础组件的运行；</li></ul><div class="notion-text notion-block-cbc662ddfaa74c1fb7412d204df195db">而Java中提供了Timer以及ScheduledThreadPoolExecutor组件作为定时任务的解决方案，我们可以方便地通过组件来运行定时任务，这篇文章我会基于自己使用定时线程池的经验对定时任务的合理运行进行总结。</div><hr class="notion-hr notion-block-a2f85e5e762b41bb870e72e2c4d268bf"/><h2 class="notion-h notion-h1 notion-block-be6be8f301bd40d597313f5f7ac240dc" data-id="be6be8f301bd40d597313f5f7ac240dc"><span><div id="be6be8f301bd40d597313f5f7ac240dc" class="notion-header-anchor"></div><a class="notion-hash-link" href="#be6be8f301bd40d597313f5f7ac240dc" title="定时任务的解决方案介绍"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">定时任务的解决方案介绍</span></span></h2><h3 class="notion-h notion-h2 notion-block-cf880233cea74444b71f742f28473d7c" data-id="cf880233cea74444b71f742f28473d7c"><span><div id="cf880233cea74444b71f742f28473d7c" class="notion-header-anchor"></div><a class="notion-hash-link" href="#cf880233cea74444b71f742f28473d7c" title="Timer组件"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">Timer组件</span></span></h3><div class="notion-text notion-block-75853fbc70924b9588fedf9e71f3c11c">Timer组件是Java在1.3版本提出的定时任务的解决方案，该实例会绑定一个后台线程来执行定时任务，线程数量无法调整，多个相同类型的任务提交到一个Timer执行，任务执行耗时会影响其他任务的执行。我理解该组件是JUC包未设计之前的历史解决方案，对于当前定时任务的技术选型个人更推荐ScheduledExecutorService，后面我对从多个角度对二者进行对比。</div><h3 class="notion-h notion-h2 notion-block-7c91d6130f544bdca8436ea25d2b2029" data-id="7c91d6130f544bdca8436ea25d2b2029"><span><div id="7c91d6130f544bdca8436ea25d2b2029" class="notion-header-anchor"></div><a class="notion-hash-link" href="#7c91d6130f544bdca8436ea25d2b2029" title="ScheduledExecutorService组件"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">ScheduledExecutorService组件</span></span></h3><div class="notion-text notion-block-f4569dd34b8847c1a14ad16be06777ab">ScheduledExecutorService属于对ExecutorService的扩展，通过查看其实现类ScheduledThreadPoolExecutor实例的源码能够发现，该线程池在构造的时候不支持指定内部的任务队列，而是直接在构造过程中指定使用内部队列DelayedWorkQueue作为任务队列，这是其与其他普通线程池最大的区别，也是该组件能够实现任务延迟处理的关键所在。</div><div class="notion-text notion-block-8311bd517b0540efbc49b2a88f3ce2dc">针对定时任务，我们最常使用的就是通过指定任务的<b>执行周期</b>来将任务提交到ScheduledThreadPoolExecutor实例中，对于调用者来说，将任务提交到该线程池之后就不需要关注其他情况，而且能够通过任务对应的ScheduledFutureTask来取消定时任务。</div><div class="notion-text notion-block-3033798329b34636aaafe5790955ce91">这里不会介绍最基础的API使用，相信大家通过日常使用能够很快上手，这里我来解答一个使用ScheduledThreadPoolExecutor时最常见的问题：通过scheduleAtFixedRate与scheduleWithFixedDelay提交任务执行的差异在哪里？下面是我针对这两个API的简单测试用例，通过运行测试用例的输出可以得到答案。</div><a target="_blank" rel="noopener noreferrer" href="https://github.com/geekeritcom/SourceCodeRun/blob/916a57ad3a0d0e17e053d2e84050a49fccf2ce8f/JavaSourceCodeRun/src/test/java/com/geekerit/juc/threadpool/ThreadPoolScheduleAPITest.java" class="notion-external notion-external-block notion-row notion-block-d9080847fc5f4d699e0c921f8af137de"><div class="notion-external-image"><svg viewBox="0 0 260 260"><g><path d="M128.00106,0 C57.3172926,0 0,57.3066942 0,128.00106 C0,184.555281 36.6761997,232.535542 87.534937,249.460899 C93.9320223,250.645779 96.280588,246.684165 96.280588,243.303333 C96.280588,240.251045 96.1618878,230.167899 96.106777,219.472176 C60.4967585,227.215235 52.9826207,204.369712 52.9826207,204.369712 C47.1599584,189.574598 38.770408,185.640538 38.770408,185.640538 C27.1568785,177.696113 39.6458206,177.859325 39.6458206,177.859325 C52.4993419,178.762293 59.267365,191.04987 59.267365,191.04987 C70.6837675,210.618423 89.2115753,204.961093 96.5158685,201.690482 C97.6647155,193.417512 100.981959,187.77078 104.642583,184.574357 C76.211799,181.33766 46.324819,170.362144 46.324819,121.315702 C46.324819,107.340889 51.3250588,95.9223682 59.5132437,86.9583937 C58.1842268,83.7344152 53.8029229,70.715562 60.7532354,53.0843636 C60.7532354,53.0843636 71.5019501,49.6441813 95.9626412,66.2049595 C106.172967,63.368876 117.123047,61.9465949 128.00106,61.8978432 C138.879073,61.9465949 149.837632,63.368876 160.067033,66.2049595 C184.49805,49.6441813 195.231926,53.0843636 195.231926,53.0843636 C202.199197,70.715562 197.815773,83.7344152 196.486756,86.9583937 C204.694018,95.9223682 209.660343,107.340889 209.660343,121.315702 C209.660343,170.478725 179.716133,181.303747 151.213281,184.472614 C155.80443,188.444828 159.895342,196.234518 159.895342,208.176593 C159.895342,225.303317 159.746968,239.087361 159.746968,243.303333 C159.746968,246.709601 162.05102,250.70089 168.53925,249.443941 C219.370432,232.499507 256,184.536204 256,128.00106 C256,57.3066942 198.691187,0 128.00106,0 Z M47.9405593,182.340212 C47.6586465,182.976105 46.6581745,183.166873 45.7467277,182.730227 C44.8183235,182.312656 44.2968914,181.445722 44.5978808,180.80771 C44.8734344,180.152739 45.876026,179.97045 46.8023103,180.409216 C47.7328342,180.826786 48.2627451,181.702199 47.9405593,182.340212 Z M54.2367892,187.958254 C53.6263318,188.524199 52.4329723,188.261363 51.6232682,187.366874 C50.7860088,186.474504 50.6291553,185.281144 51.2480912,184.70672 C51.8776254,184.140775 53.0349512,184.405731 53.8743302,185.298101 C54.7115892,186.201069 54.8748019,187.38595 54.2367892,187.958254 Z M58.5562413,195.146347 C57.7719732,195.691096 56.4895886,195.180261 55.6968417,194.042013 C54.9125733,192.903764 54.9125733,191.538713 55.713799,190.991845 C56.5086651,190.444977 57.7719732,190.936735 58.5753181,192.066505 C59.3574669,193.22383 59.3574669,194.58888 58.5562413,195.146347 Z M65.8613592,203.471174 C65.1597571,204.244846 63.6654083,204.03712 62.5716717,202.981538 C61.4524999,201.94927 61.1409122,200.484596 61.8446341,199.710926 C62.5547146,198.935137 64.0575422,199.15346 65.1597571,200.200564 C66.2704506,201.230712 66.6095936,202.705984 65.8613592,203.471174 Z M75.3025151,206.281542 C74.9930474,207.284134 73.553809,207.739857 72.1039724,207.313809 C70.6562556,206.875043 69.7087748,205.700761 70.0012857,204.687571 C70.302275,203.678621 71.7478721,203.20382 73.2083069,203.659543 C74.6539041,204.09619 75.6035048,205.261994 75.3025151,206.281542 Z M86.046947,207.473627 C86.0829806,208.529209 84.8535871,209.404622 83.3316829,209.4237 C81.8013,209.457614 80.563428,208.603398 80.5464708,207.564772 C80.5464708,206.498591 81.7483088,205.631657 83.2786917,205.606221 C84.8005962,205.576546 86.046947,206.424403 86.046947,207.473627 Z M96.6021471,207.069023 C96.7844366,208.099171 95.7267341,209.156872 94.215428,209.438785 C92.7295577,209.710099 91.3539086,209.074206 91.1652603,208.052538 C90.9808515,206.996955 92.0576306,205.939253 93.5413813,205.66582 C95.054807,205.402984 96.4092596,206.021919 96.6021471,207.069023 Z" fill="#161614"></path></g></svg></div><div class="notion-external-description"><div class="notion-external-title">ThreadPoolScheduleAPITest.java</div><div class="notion-external-subtitle"><span>geekeritcom</span></div></div></a><ul class="notion-list notion-list-disc notion-block-6e82b60b726f45f39778bdd5058b3cf6"><li>fixRate：任务执行周期会受到任务耗时影响，当任务执行耗时超出指定的周期时，上次任务执行结束后线程池会立即开始执行新任务；</li></ul><ul class="notion-list notion-list-disc notion-block-4c9f348bf9174a8f969a5aaf74a2dad0"><li>fixDelay：任务执行周期不受任务执行耗时的影响，每次的任务执行都会保持固定的周期时长间隔</li></ul><div class="notion-text notion-block-2f1139fbdf784c86af914a5135331830">下图是我根据这两个API的主要差别绘制的逻辑示意图，再结合上述相关的测试代码，相信很好理解。</div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-43771615a5994b598c6c4f1714d408ea"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://image.run-run.vip/2024/08/01/schedulePoolAPI.png?t=43771615-a599-4b59-8c6c-4f1714d408ea" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-blank notion-block-bfbe7d4ff441466591338584b74e7e5a"> </div><h3 class="notion-h notion-h2 notion-block-d8bc8952203842558875143741cffddf" data-id="d8bc8952203842558875143741cffddf"><span><div id="d8bc8952203842558875143741cffddf" class="notion-header-anchor"></div><a class="notion-hash-link" href="#d8bc8952203842558875143741cffddf" title="Timer与ScheduledExecutorService简单对比"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">Timer与ScheduledExecutorService简单对比</span></span></h3><table class="notion-simple-table notion-block-b3494c93f2f240efa85bea82e5fc547a"><tbody><tr class="notion-simple-table-row notion-block-2daaa7fb7d29438993e74f8530ae4f7f"><td class="" style="width:278px"><div class="notion-simple-table-cell">ㅤ</div></td><td class="" style="width:120px"><div class="notion-simple-table-cell">线程数量</div></td><td class="" style="width:120px"><div class="notion-simple-table-cell">底层实现</div></td><td class="" style="width:120px"><div class="notion-simple-table-cell">任务</div></td><td class="" style="width:120px"><div class="notion-simple-table-cell">特点</div></td><td class="" style="width:301px"><div class="notion-simple-table-cell">任务控制</div></td></tr><tr class="notion-simple-table-row notion-block-abd5a418adc94cf99aba5caf4bbd2dfd"><td class="" style="width:278px"><div class="notion-simple-table-cell">Timer</div></td><td class="" style="width:120px"><div class="notion-simple-table-cell">1</div></td><td class="" style="width:120px"><div class="notion-simple-table-cell">单个线程</div></td><td class="" style="width:120px"><div class="notion-simple-table-cell">TimerTask抽象类的子类</div></td><td class="" style="width:120px"><div class="notion-simple-table-cell">实例创建时启动线程；
不能细粒度控制任务，无法获取队列任务；
单线程串行执行</div></td><td class="" style="width:301px"><div class="notion-simple-table-cell">无法取消单个任务</div></td></tr><tr class="notion-simple-table-row notion-block-634659f442234e0a89570119d910a306"><td class="" style="width:278px"><div class="notion-simple-table-cell">ScheduledExecutorService</div></td><td class="" style="width:120px"><div class="notion-simple-table-cell">自定义</div></td><td class="" style="width:120px"><div class="notion-simple-table-cell">线程池</div></td><td class="" style="width:120px"><div class="notion-simple-table-cell">Runnable接口的实现</div></td><td class="" style="width:120px"><div class="notion-simple-table-cell">任务提交时尝试创建线程；
可以获取队列任务
多线程并行执行，并发能力更高</div></td><td class="" style="width:301px"><div class="notion-simple-table-cell">可以利用任务的Future取消单个任务</div></td></tr></tbody></table><h3 class="notion-h notion-h2 notion-block-3d7f2c1a5d294b239dba52ee138e1a3a" data-id="3d7f2c1a5d294b239dba52ee138e1a3a"><span><div id="3d7f2c1a5d294b239dba52ee138e1a3a" class="notion-header-anchor"></div><a class="notion-hash-link" href="#3d7f2c1a5d294b239dba52ee138e1a3a" title="定时任务的“丢失”"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">定时任务的“丢失”</span></span></h3><div class="notion-text notion-block-042a41a581af42d3888d6659db77819c">无论采取哪种方案来实现定时任务的运行，都需要注意任务的异常捕获等级不够，导致的定时任务终止执行，表象就是代码中没有打印任何异常，任务也不再执行。</div><div class="notion-text notion-block-8cb435013aec47089081ee18e051e7c1">我在项目中曾经遇到过的问题是，某个定时任务的处理链路非常长，某天测试人员反馈定时任务偶发无法执行，我查看日志发现没有任何异常信息，于是将线程信息dump后进行分析，发现线程进入阻塞状态。但是为什么定时线程会进入阻塞状态不再获取任务呢？关键是日志里也没有打印任何异常信息啊？在分析代码的各种情况确认没有问题后，怀疑难道是出现了更高级别的异常，导致没有捕获？</div><div class="notion-text notion-block-3268e2aeb56f4c229a0e87f64e4e3cfa">于是提高了异常捕获等级后重新测试，终于发现是由于该定时线程在某些情况下会出现处理链路很长，导致出现了StackOverflowError的错误，但是之前的代码只处理了Exception级别的异常，导致定时任务会被“丢失”。</div><div class="notion-text notion-block-b87c706501534c9bbc577c1b6e03dde6">示例代码如下，因此在日常开发中我们一定要注意定时任务的异常处理。</div><a target="_blank" rel="noopener noreferrer" href="https://github.com/geekeritcom/SourceCodeRun/blob/916a57ad3a0d0e17e053d2e84050a49fccf2ce8f/SpringScheduleTaskTest/src/test/java/com/geekerit/config/ScheduleTaskThrowErrorTest.java" class="notion-external notion-external-block notion-row notion-block-2fb473ddc9bf4a2a9b89c09c84314d9e"><div class="notion-external-image"><svg viewBox="0 0 260 260"><g><path d="M128.00106,0 C57.3172926,0 0,57.3066942 0,128.00106 C0,184.555281 36.6761997,232.535542 87.534937,249.460899 C93.9320223,250.645779 96.280588,246.684165 96.280588,243.303333 C96.280588,240.251045 96.1618878,230.167899 96.106777,219.472176 C60.4967585,227.215235 52.9826207,204.369712 52.9826207,204.369712 C47.1599584,189.574598 38.770408,185.640538 38.770408,185.640538 C27.1568785,177.696113 39.6458206,177.859325 39.6458206,177.859325 C52.4993419,178.762293 59.267365,191.04987 59.267365,191.04987 C70.6837675,210.618423 89.2115753,204.961093 96.5158685,201.690482 C97.6647155,193.417512 100.981959,187.77078 104.642583,184.574357 C76.211799,181.33766 46.324819,170.362144 46.324819,121.315702 C46.324819,107.340889 51.3250588,95.9223682 59.5132437,86.9583937 C58.1842268,83.7344152 53.8029229,70.715562 60.7532354,53.0843636 C60.7532354,53.0843636 71.5019501,49.6441813 95.9626412,66.2049595 C106.172967,63.368876 117.123047,61.9465949 128.00106,61.8978432 C138.879073,61.9465949 149.837632,63.368876 160.067033,66.2049595 C184.49805,49.6441813 195.231926,53.0843636 195.231926,53.0843636 C202.199197,70.715562 197.815773,83.7344152 196.486756,86.9583937 C204.694018,95.9223682 209.660343,107.340889 209.660343,121.315702 C209.660343,170.478725 179.716133,181.303747 151.213281,184.472614 C155.80443,188.444828 159.895342,196.234518 159.895342,208.176593 C159.895342,225.303317 159.746968,239.087361 159.746968,243.303333 C159.746968,246.709601 162.05102,250.70089 168.53925,249.443941 C219.370432,232.499507 256,184.536204 256,128.00106 C256,57.3066942 198.691187,0 128.00106,0 Z M47.9405593,182.340212 C47.6586465,182.976105 46.6581745,183.166873 45.7467277,182.730227 C44.8183235,182.312656 44.2968914,181.445722 44.5978808,180.80771 C44.8734344,180.152739 45.876026,179.97045 46.8023103,180.409216 C47.7328342,180.826786 48.2627451,181.702199 47.9405593,182.340212 Z M54.2367892,187.958254 C53.6263318,188.524199 52.4329723,188.261363 51.6232682,187.366874 C50.7860088,186.474504 50.6291553,185.281144 51.2480912,184.70672 C51.8776254,184.140775 53.0349512,184.405731 53.8743302,185.298101 C54.7115892,186.201069 54.8748019,187.38595 54.2367892,187.958254 Z M58.5562413,195.146347 C57.7719732,195.691096 56.4895886,195.180261 55.6968417,194.042013 C54.9125733,192.903764 54.9125733,191.538713 55.713799,190.991845 C56.5086651,190.444977 57.7719732,190.936735 58.5753181,192.066505 C59.3574669,193.22383 59.3574669,194.58888 58.5562413,195.146347 Z M65.8613592,203.471174 C65.1597571,204.244846 63.6654083,204.03712 62.5716717,202.981538 C61.4524999,201.94927 61.1409122,200.484596 61.8446341,199.710926 C62.5547146,198.935137 64.0575422,199.15346 65.1597571,200.200564 C66.2704506,201.230712 66.6095936,202.705984 65.8613592,203.471174 Z M75.3025151,206.281542 C74.9930474,207.284134 73.553809,207.739857 72.1039724,207.313809 C70.6562556,206.875043 69.7087748,205.700761 70.0012857,204.687571 C70.302275,203.678621 71.7478721,203.20382 73.2083069,203.659543 C74.6539041,204.09619 75.6035048,205.261994 75.3025151,206.281542 Z M86.046947,207.473627 C86.0829806,208.529209 84.8535871,209.404622 83.3316829,209.4237 C81.8013,209.457614 80.563428,208.603398 80.5464708,207.564772 C80.5464708,206.498591 81.7483088,205.631657 83.2786917,205.606221 C84.8005962,205.576546 86.046947,206.424403 86.046947,207.473627 Z M96.6021471,207.069023 C96.7844366,208.099171 95.7267341,209.156872 94.215428,209.438785 C92.7295577,209.710099 91.3539086,209.074206 91.1652603,208.052538 C90.9808515,206.996955 92.0576306,205.939253 93.5413813,205.66582 C95.054807,205.402984 96.4092596,206.021919 96.6021471,207.069023 Z" fill="#161614"></path></g></svg></div><div class="notion-external-description"><div class="notion-external-title">ScheduleTaskThrowErrorTest.java</div><div class="notion-external-subtitle"><span>geekeritcom</span></div></div></a><hr class="notion-hr notion-block-8a94c9418cc64be3a88230754a1d3924"/><h2 class="notion-h notion-h1 notion-block-2fffed7290f54bfe97eba10ecfe76cc4" data-id="2fffed7290f54bfe97eba10ecfe76cc4"><span><div id="2fffed7290f54bfe97eba10ecfe76cc4" class="notion-header-anchor"></div><a class="notion-hash-link" href="#2fffed7290f54bfe97eba10ecfe76cc4" title="Spring定时任务"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">Spring定时任务</span></span></h2><div class="notion-text notion-block-4811a7b084f64f3d9307e371bae83535">如果我们在Spring框架下进行开发，Spring也提供了定时任务的解决方案，但是使用时一定要了解清楚其实现原理，否则很可能会踩坑。</div><div class="notion-text notion-block-3557ff78355341148648c274326d5c9e">我们日常使用Spring框架进行开发时，可以使用@EnableScheduling注解启用内置的定时任务机制，利用@Scheduled注解能够指定任务的周期等信息，使用还是非常方便的。</div><h3 class="notion-h notion-h2 notion-block-8b1ef495727b475b91cd6b0bbb433d34" data-id="8b1ef495727b475b91cd6b0bbb433d34"><span><div id="8b1ef495727b475b91cd6b0bbb433d34" class="notion-header-anchor"></div><a class="notion-hash-link" href="#8b1ef495727b475b91cd6b0bbb433d34" title="警惕默认方案的坑"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">警惕默认方案的坑</span></span></h3><div class="notion-text notion-block-9e5212a4403e4b69a2a6ad0006789508">需要注意的是，使用Spring框架提供的定时任务默认情况下内部<b>只会创建一个线程</b>的线程池，因此如果业务中多个地方同时使用默认的定时线程池，某个任务的长耗时操作就会影响其他业务线程的正常执行。</div><details class="notion-toggle notion-block-73a764220eb440b39c0b0cacbdbcb413"><summary>为什么Spring默认情况下只会创建单线程的定时任务线程池呢</summary><div><div class="notion-text notion-block-b04320b098f54aaf887e11129e437540">我们使用Spring提供的定时任务机制，一定要在配置类添加@EnableScheduling注解，下面是该注解上的部分JavaDoc描述</div><blockquote class="notion-quote notion-block-cd2d856044274fd4877c9aded3d45d50"><div>By default, will be searching for an associated scheduler definition: either a unique org.springframework.scheduling.TaskScheduler bean in the context,or a TaskScheduler bean named &quot;taskScheduler&quot; otherwise; the same lookup will also be performed for a java.util.concurrent.ScheduledExecutorService bean. If neither of the two is resolvable, a local single-threaded default scheduler will be created and used within the registrar.</div></blockquote><div class="notion-text notion-block-7d6579e800bc4f17aee308b5b05e9ce0">上述意思非常明确，默认情况下会去扫描类型为TaskScheduler的bean，以及ScheduledExecutorService类型的bean，如果二者都没有扫描到，则创建一个单线程的定时线程池注册到Spring容器中。</div></div></details><a target="_blank" rel="noopener noreferrer" href="https://github.com/geekeritcom/SourceCodeRun/blob/916a57ad3a0d0e17e053d2e84050a49fccf2ce8f/SpringScheduleTaskTest/src/main/java/com/geekerit/ScheduleTaskTest.java" class="notion-external notion-external-block notion-row notion-block-a9699a7fc07642708f540958c64f6739"><div class="notion-external-image"><svg viewBox="0 0 260 260"><g><path d="M128.00106,0 C57.3172926,0 0,57.3066942 0,128.00106 C0,184.555281 36.6761997,232.535542 87.534937,249.460899 C93.9320223,250.645779 96.280588,246.684165 96.280588,243.303333 C96.280588,240.251045 96.1618878,230.167899 96.106777,219.472176 C60.4967585,227.215235 52.9826207,204.369712 52.9826207,204.369712 C47.1599584,189.574598 38.770408,185.640538 38.770408,185.640538 C27.1568785,177.696113 39.6458206,177.859325 39.6458206,177.859325 C52.4993419,178.762293 59.267365,191.04987 59.267365,191.04987 C70.6837675,210.618423 89.2115753,204.961093 96.5158685,201.690482 C97.6647155,193.417512 100.981959,187.77078 104.642583,184.574357 C76.211799,181.33766 46.324819,170.362144 46.324819,121.315702 C46.324819,107.340889 51.3250588,95.9223682 59.5132437,86.9583937 C58.1842268,83.7344152 53.8029229,70.715562 60.7532354,53.0843636 C60.7532354,53.0843636 71.5019501,49.6441813 95.9626412,66.2049595 C106.172967,63.368876 117.123047,61.9465949 128.00106,61.8978432 C138.879073,61.9465949 149.837632,63.368876 160.067033,66.2049595 C184.49805,49.6441813 195.231926,53.0843636 195.231926,53.0843636 C202.199197,70.715562 197.815773,83.7344152 196.486756,86.9583937 C204.694018,95.9223682 209.660343,107.340889 209.660343,121.315702 C209.660343,170.478725 179.716133,181.303747 151.213281,184.472614 C155.80443,188.444828 159.895342,196.234518 159.895342,208.176593 C159.895342,225.303317 159.746968,239.087361 159.746968,243.303333 C159.746968,246.709601 162.05102,250.70089 168.53925,249.443941 C219.370432,232.499507 256,184.536204 256,128.00106 C256,57.3066942 198.691187,0 128.00106,0 Z M47.9405593,182.340212 C47.6586465,182.976105 46.6581745,183.166873 45.7467277,182.730227 C44.8183235,182.312656 44.2968914,181.445722 44.5978808,180.80771 C44.8734344,180.152739 45.876026,179.97045 46.8023103,180.409216 C47.7328342,180.826786 48.2627451,181.702199 47.9405593,182.340212 Z M54.2367892,187.958254 C53.6263318,188.524199 52.4329723,188.261363 51.6232682,187.366874 C50.7860088,186.474504 50.6291553,185.281144 51.2480912,184.70672 C51.8776254,184.140775 53.0349512,184.405731 53.8743302,185.298101 C54.7115892,186.201069 54.8748019,187.38595 54.2367892,187.958254 Z M58.5562413,195.146347 C57.7719732,195.691096 56.4895886,195.180261 55.6968417,194.042013 C54.9125733,192.903764 54.9125733,191.538713 55.713799,190.991845 C56.5086651,190.444977 57.7719732,190.936735 58.5753181,192.066505 C59.3574669,193.22383 59.3574669,194.58888 58.5562413,195.146347 Z M65.8613592,203.471174 C65.1597571,204.244846 63.6654083,204.03712 62.5716717,202.981538 C61.4524999,201.94927 61.1409122,200.484596 61.8446341,199.710926 C62.5547146,198.935137 64.0575422,199.15346 65.1597571,200.200564 C66.2704506,201.230712 66.6095936,202.705984 65.8613592,203.471174 Z M75.3025151,206.281542 C74.9930474,207.284134 73.553809,207.739857 72.1039724,207.313809 C70.6562556,206.875043 69.7087748,205.700761 70.0012857,204.687571 C70.302275,203.678621 71.7478721,203.20382 73.2083069,203.659543 C74.6539041,204.09619 75.6035048,205.261994 75.3025151,206.281542 Z M86.046947,207.473627 C86.0829806,208.529209 84.8535871,209.404622 83.3316829,209.4237 C81.8013,209.457614 80.563428,208.603398 80.5464708,207.564772 C80.5464708,206.498591 81.7483088,205.631657 83.2786917,205.606221 C84.8005962,205.576546 86.046947,206.424403 86.046947,207.473627 Z M96.6021471,207.069023 C96.7844366,208.099171 95.7267341,209.156872 94.215428,209.438785 C92.7295577,209.710099 91.3539086,209.074206 91.1652603,208.052538 C90.9808515,206.996955 92.0576306,205.939253 93.5413813,205.66582 C95.054807,205.402984 96.4092596,206.021919 96.6021471,207.069023 Z" fill="#161614"></path></g></svg></div><div class="notion-external-description"><div class="notion-external-title">ScheduleTaskTest.java</div><div class="notion-external-subtitle"><span>geekeritcom</span></div></div></a><div class="notion-text notion-block-d3d554c3f633465898dfee1ce1603f9a">使用上述测试代码运行后会发现，task2并不会按照我们预期每两秒执行一次，这就是因为task1执行耗时过长导致线程被占用，任务只能被放入等待队列中。</div><div class="notion-text notion-block-264585a4100640b4a4064b9eb82838b0">那如果我们想要使用Spring提供的定时任务解决方案，如何解决这种问题呢？根据Spring官方文档可以得到，解决方案有以下几种：</div><ol start="1" class="notion-list notion-list-numbered notion-block-493b1f344ce145c1858503f1da387610"><li>通过配置文件指定Spring内置定时任务线程池的线程数量</li><ol class="notion-list notion-list-numbered notion-block-493b1f344ce145c1858503f1da387610"></ol></ol><ol start="2" class="notion-list notion-list-numbered notion-block-aa499794fe904e769ffd879705c1a759"><li>创建TaskScheduler组件注入Spring容器</li></ol><ol start="3" class="notion-list notion-list-numbered notion-block-3c1bd24024c94254bb4e83055023f5f4"><li>创建ScheduledExecutorService组件注入Spring容器</li></ol><div class="notion-text notion-block-bb7bdd2e99bd4601bb95093cb8de241f">这几种方案我也亲身验证了，并放在了上述测试用例的工程中。</div><hr class="notion-hr notion-block-8c9e77ba5ae04e0c8722807e94ff00c1"/><h3 class="notion-h notion-h2 notion-block-4115678471924f2cb9f53b33603a38e1" data-id="4115678471924f2cb9f53b33603a38e1"><span><div id="4115678471924f2cb9f53b33603a38e1" class="notion-header-anchor"></div><a class="notion-hash-link" href="#4115678471924f2cb9f53b33603a38e1" title="Spring定时线程池的装配"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">Spring定时线程池的装配</span></span></h3><div class="notion-text notion-block-bce4e135092643a2b25ac9f46a8bc551">我对单线程线程池如何组装的一点探究：定时线程池组件由ScheduledExecutorFactoryBean组件负责创建，该组件继承于ExecutorConfigurationSupport，在Spring容器启动后会触发组件的初始化方法。</div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-ff3b363ba2e64acbba809a584f99fa62"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://image.run-run.vip/2024/08/01/springSchedule01.png?t=ff3b363b-a2e6-4acb-ba80-9a584f99fa62" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-text notion-block-9edc32132255446d88d1ddd868dc25bd">最终会由ScheduledExecutorFactoryBean组件来创建线程池</div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-8572567c046b415ea5e3369a54aa47cc"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://image.run-run.vip/2024/08/01/springSchedule02.png?t=8572567c-046b-415e-a5e3-369a54aa47cc" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-text notion-block-ae60d1dc7226481e8b45ba20a931b3a9">线程池的实例化</div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-d6d173f9460949c9a783a7f5c9f9ef97"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://image.run-run.vip/2024/08/01/springSchedule03.png?t=d6d173f9-4609-49c9-a783-a7f5c9f9ef97" alt="notion image" loading="lazy" decoding="async"/></div></figure></div></main></div>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[夜游西湖]]></title>
            <link>https://blog.geekerit.com/article/6736ebe7-864f-4b13-a578-5e0061395e49</link>
            <guid>https://blog.geekerit.com/article/6736ebe7-864f-4b13-a578-5e0061395e49</guid>
            <pubDate>Fri, 05 Jul 2024 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<div id="notion-article" class="mx-auto overflow-hidden "><main class="notion light-mode notion-page notion-full-width notion-block-6736ebe7864f4b13a5785e0061395e49"><div class="notion-viewport"></div><div class="notion-collection-page-properties"></div><div class="notion-text notion-block-fe2c685be1f846a5bc6b60c2a5475dfa">最近杭州的天气真的非常炙热，正巧逛小红书发现了有博主分享的可以夜游西湖，趁着周五就来了一次说走就走的夜游。</div><div class="notion-text notion-block-f7fdb9e89acd475facce0d3e695b2bb7">这次去了西湖边两个地方，一个叫宝石山，是西湖边一座并不高的山峰，站在山上可以眺望西湖夜景；另一个就是去了灵隐寺，也是凑巧在小红书看到，灵隐寺只有在每个月特定的时间才会开放夜游，而且夜游灵隐寺还有一点好处就是，不再需要购买飞来峰的门票（如果白天去灵隐寺从飞来峰入口进去就得买票）。</div><div class="notion-text notion-block-9e097f0fc9534cd59404b5e58dcdd38b">在西湖附近找停车位就得半小时，从停车位走到宝石山入口已经汗流浃背了，夏天的感觉就是离开空调就是汗。</div><div class="notion-text notion-block-e7aaa66c303343199e9f5ee2fe816298">下面是在宝石山上往下望向西湖的夜景（手机像素太差了，看个意境吧）。</div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-3986368789f4406a82728638f4ee736a"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://static.geekerit.com/travels/2024/20240705xihu/baoshishan.jpeg?t=39863687-89f4-406a-8272-8638f4ee736a" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-text notion-block-e3eae4eed0084c34b5862e99c683891f">山上蚊子太多了，简单呆了片刻就马上启程去了灵隐寺。虽说是夜游，但可能大家都害怕大白天的高温，夜游灵隐寺的人也非常多，在我们晚上十二点左右离开的时候依旧有很多人刚刚从入口进来，看来错峰出行的理念深入人心。</div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-cba623ddc0c541a8bd5a8cb47c1f2285"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://static.geekerit.com/travels/2024/20240705xihu/lingyinsi02.jpg?t=cba623dd-c0c5-41a8-bd5a-8cb47c1f2285" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-blank notion-block-383e32119d034138bdbe9558eb512fc0"> </div><div class="notion-text notion-block-4e4992b6f29340848fad796879d79f3c">灵隐寺入口</div><div class="notion-blank notion-block-191bd5de0d214cd5ac8a2a6660585c3d"> </div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-6fc7248566d2485c8d7dcd2e3ea14c22"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://static.geekerit.com/travels/2024/20240705xihu/lingyinsi03.jpg?t=6fc72485-66d2-485c-8d7d-cd2e3ea14c22" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-blank notion-block-11a8f0dc30564073b21ecd12545beb07"> </div><div class="notion-text notion-block-b90fc8710938472bb7d5e8f237453844">灵隐寺内</div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-b5af26e189d245f09b2c4b8c509d3051"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://static.geekerit.com/travels/2024/20240705xihu/lingyinsi04.jpg?t=b5af26e1-89d2-45f0-9b2c-4b8c509d3051" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-blank notion-block-e14bba038f3d460cb11dc6a232dd4036"> </div><div class="notion-blank notion-block-d935de2e6f864a588fd64177f0c8b955"> </div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-b2bc0741d11e4f5f9e722c59c8814fc1"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://static.geekerit.com/travels/2024/20240705xihu/lingyinsi05.jpg?t=b2bc0741-d11e-4f5f-9e72-2c59c8814fc1" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-blank notion-block-f903c30565dc4d81b007b14403259608"> </div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-afce3f43b78d40c5877a9877bbf2e18b"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://static.geekerit.com/travels/2024/20240705xihu/lingyinsi06.jpg?t=afce3f43-b78d-40c5-877a-9877bbf2e18b" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-blank notion-block-a1a25d194d5d427097a4dcf055b7edb0"> </div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-68cc91060d494ec1bc4fca3ace0a0400"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://static.geekerit.com/travels/2024/20240705xihu/lingyinsi07.jpg?t=68cc9106-0d49-4ec1-bc4f-ca3ace0a0400" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-blank notion-block-ea721ef0de734df8a87c33610357cc78"> </div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-d54a1ddcde674f07b67a55868e4ce77d"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://static.geekerit.com/travels/2024/20240705xihu/lingyinsi08.jpg?t=d54a1ddc-de67-4f07-b67a-55868e4ce77d" alt="notion image" loading="lazy" decoding="async"/></div></figure><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-0d8c9890d1db468fa562fa01a99af67a"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://static.geekerit.com/travels/2024/20240705xihu/lingyinsi09.jpg?t=0d8c9890-d1db-468f-a562-fa01a99af67a" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-text notion-block-45d20fca33f84d2ca94ec79a1272318d">最后，在灵隐寺缠着我老婆求了十八籽，据说很灵验。</div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-d84d1363de6b4c9b92956af347e89283"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://static.geekerit.com/travels/2024/20240705xihu/lingyinsi10.jpg?t=d84d1363-de6b-4c9b-9295-6af347e89283" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-blank notion-block-f908b60eef594ff68886db953c110373"> </div></main></div>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[春天的感觉]]></title>
            <link>https://blog.geekerit.com/article/0dec0fd9-5798-44ca-9d79-7e570ebe7780</link>
            <guid>https://blog.geekerit.com/article/0dec0fd9-5798-44ca-9d79-7e570ebe7780</guid>
            <pubDate>Mon, 25 Mar 2024 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<div id="notion-article" class="mx-auto overflow-hidden "><main class="notion light-mode notion-page notion-block-0dec0fd9579844ca9d797e570ebe7780"><div class="notion-viewport"></div><div class="notion-collection-page-properties"></div><div class="notion-blank notion-block-447e266391b44035920a8da9060adfc9"> </div><div class="notion-text notion-block-2fd094d1701c4385aa59928b0103e479">杭州的春天总是非常短暂，好像每年都是冬天刚过就有了夏天的感觉，所以在这短暂的春日时光里，留下一些照片作为纪念。</div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-4210d17ea1f14f91a0d6b0f1204ee871"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://static.geekerit.com/travels%2F2024%2F20240325%2Fspring01.jpeg?t=4210d17e-a1f1-4f91-a0d6-b0f1204ee871" alt="notion image" loading="lazy" decoding="async"/></div></figure><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-7a878e44f64c4b4d93b8d3ca700bf6c4"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://static.geekerit.com/travels%2F2024%2F20240325%2Fspring03.jpeg?t=7a878e44-f64c-4b4d-93b8-d3ca700bf6c4" alt="notion image" loading="lazy" decoding="async"/></div></figure><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-19fb5f6c309a45dbbf1b45ae29161cdd"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://static.geekerit.com/travels%2F2024%2F20240325%2Fspring02.jpeg?t=19fb5f6c-309a-45db-bf1b-45ae29161cdd" alt="notion image" loading="lazy" decoding="async"/></div></figure><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-45f6a4ff28f6476b9da809dab0c14d8b"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://static.geekerit.com/travels%2F2024%2F20240325%2Fspring04.jpeg?t=45f6a4ff-28f6-476b-9da8-09dab0c14d8b" alt="notion image" loading="lazy" decoding="async"/></div></figure><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-a56ce983e708479f97b8f0d9b11ba50c"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://static.geekerit.com/travels%2F2024%2F20240325%2Fspring05.jpeg?t=a56ce983-e708-479f-97b8-f0d9b11ba50c" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-blank notion-block-7413456555f6469d9fd28f7395f1a0d1"> </div><div class="notion-blank notion-block-b966981b19b04277bc839fa805adf5ee"> </div><div class="notion-text notion-block-223a428ccb694c41a0367a07928451fe">2024年03月29日更新</div><div class="notion-text notion-block-190bce75ca5d4d94aa1c5323dc09b363">今天早上又去公园转了一圈，很多花都快开过了，抓紧再拍了一些照片。</div><div class="notion-blank notion-block-85454fe725454f808e946c2203542a8b"> </div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-2cc55bdff5564e12a37b52e04becee2d"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://static.geekerit.com/travels%2F2024%2F20240329%2Fspring01.jpeg?t=2cc55bdf-f556-4e12-a37b-52e04becee2d" alt="notion image" loading="lazy" decoding="async"/></div></figure><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-e306456c7f80416bad0b141f9a3dd6f1"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://static.geekerit.com/travels%2F2024%2F20240329%2Fspring04.jpeg?t=e306456c-7f80-416b-ad0b-141f9a3dd6f1" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-blank notion-block-607c2b773301445aaa09926e1c0bf093"> </div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-8a3e6d88c58f45a1aa8af3cdcfc54974"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://static.geekerit.com/travels%2F2024%2F20240329%2Fspring02.jpeg?t=8a3e6d88-c58f-45a1-aa8a-f3cdcfc54974" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-blank notion-block-fd16b624104549f990bcb5da7689202a"> </div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-1cb54d0f5d6c4f3798608918e59d657c"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://static.geekerit.com/travels%2F2024%2F20240329%2Fspring03.jpeg?t=1cb54d0f-5d6c-4f37-9860-8918e59d657c" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-text notion-block-99bad6ff2db748a39cdf95f3b2288cf6">勤劳的蜜蜂🐝</div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-1ab6ba450ece440ab0775b9292379c22"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://static.geekerit.com/travels%2F2024%2F20240329%2Fspring05.jpeg?t=1ab6ba45-0ece-440a-b077-5b9292379c22" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-text notion-block-cfe898ad36224f47aa1442566911602e">呆呆的xiugouer</div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-2b7a2f9e236a4294aa3d600723aae9ac"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://static.geekerit.com/travels%2F2024%2F20240329%2Fspring06.jpeg?t=2b7a2f9e-236a-4294-aa3d-600723aae9ac" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-text notion-block-56990870acb54200a9c35333bf24ee19">盛开的晚樱</div></main></div>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[项目管理之沟通管理]]></title>
            <link>https://blog.geekerit.com/article/22a5da9c-2517-4a8c-87b3-205f48c89b8d</link>
            <guid>https://blog.geekerit.com/article/22a5da9c-2517-4a8c-87b3-205f48c89b8d</guid>
            <pubDate>Wed, 27 Mar 2024 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[项目管理之风险管理]]></title>
            <link>https://blog.geekerit.com/article/490ad5c0-13cc-46c1-88e1-8219ca229790</link>
            <guid>https://blog.geekerit.com/article/490ad5c0-13cc-46c1-88e1-8219ca229790</guid>
            <pubDate>Thu, 28 Mar 2024 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[项目管理之采购管理和合同管理]]></title>
            <link>https://blog.geekerit.com/article/b9a2afc4-78ed-4a06-bf08-50ea7dc23d3e</link>
            <guid>https://blog.geekerit.com/article/b9a2afc4-78ed-4a06-bf08-50ea7dc23d3e</guid>
            <pubDate>Tue, 26 Mar 2024 00:00:00 GMT</pubDate>
        </item>
    </channel>
</rss>