diff --git a/2020/06/26/聊一下-RocketMQ-的-Consumer/index.html b/2020/06/26/聊一下-RocketMQ-的-Consumer/index.html index 8fd7c34ca4..bbbad49d97 100644 --- a/2020/06/26/聊一下-RocketMQ-的-Consumer/index.html +++ b/2020/06/26/聊一下-RocketMQ-的-Consumer/index.html @@ -1,4 +1,4 @@ -聊一下 RocketMQ 的 DefaultMQPushConsumer 源码 | Nicksxs's Blog

Nicksxs's Blog

What hurts more, the pain of hard work or the pain of regret?

聊一下 RocketMQ 的 DefaultMQPushConsumer 源码

首先看下官方的小 demo

public static void main(String[] args) throws InterruptedException, MQClientException {
+聊一下 RocketMQ 的 DefaultMQPushConsumer 源码 | Nicksxs's Blog

Nicksxs's Blog

What hurts more, the pain of hard work or the pain of regret?

聊一下 RocketMQ 的 DefaultMQPushConsumer 源码

首先看下官方的小 demo

public static void main(String[] args) throws InterruptedException, MQClientException {
 
         /*
          * Instantiate with specified consumer group name.
@@ -737,4 +737,4 @@
                 throw new RemotingTimeoutException(info);
             }
         }
-    }
0%
\ No newline at end of file + }
0%
\ No newline at end of file diff --git a/2020/07/05/聊一下-RocketMQ-的-NameServer-源码/index.html b/2020/07/05/聊一下-RocketMQ-的-NameServer-源码/index.html index 81d832b73c..71f999d24b 100644 --- a/2020/07/05/聊一下-RocketMQ-的-NameServer-源码/index.html +++ b/2020/07/05/聊一下-RocketMQ-的-NameServer-源码/index.html @@ -1,4 +1,4 @@ -聊一下 RocketMQ 的 NameServer 源码 | Nicksxs's Blog

Nicksxs's Blog

What hurts more, the pain of hard work or the pain of regret?

聊一下 RocketMQ 的 NameServer 源码

前面介绍了,nameserver相当于dubbo的注册中心,用与管理broker,broker会在启动的时候注册到nameserver,并且会发送心跳给namaserver,nameserver负责保存活跃的broker,包括master和slave,同时保存topic和topic下的队列,以及filter列表,然后为producer和consumer的请求提供服务。

启动过程

public static void main(String[] args) {
+聊一下 RocketMQ 的 NameServer 源码 | Nicksxs's Blog

Nicksxs's Blog

What hurts more, the pain of hard work or the pain of regret?

聊一下 RocketMQ 的 NameServer 源码

前面介绍了,nameserver相当于dubbo的注册中心,用与管理broker,broker会在启动的时候注册到nameserver,并且会发送心跳给namaserver,nameserver负责保存活跃的broker,包括master和slave,同时保存topic和topic下的队列,以及filter列表,然后为producer和consumer的请求提供服务。

启动过程

public static void main(String[] args) {
         main0(args);
     }
 
@@ -563,4 +563,4 @@
         response.setRemark("No topic route info in name server for the topic: " + requestHeader.getTopic()
             + FAQUrl.suggestTodo(FAQUrl.APPLY_TOPIC_URL));
         return response;
-    }

首先调用org.apache.rocketmq.namesrv.routeinfo.RouteInfoManager#pickupTopicRouteDataorg.apache.rocketmq.namesrv.routeinfo.RouteInfoManager#topicQueueTable获取到org.apache.rocketmq.common.protocol.route.QueueData这里面存了 brokerName,再通过org.apache.rocketmq.namesrv.routeinfo.RouteInfoManager#brokerAddrTable里获取到 broker 的地址信息等,然后再获取 orderMessage 的配置。

简要分析了下 RocketMQ 的 NameServer 的代码,比较粗粒度。

0%
\ No newline at end of file + }

首先调用org.apache.rocketmq.namesrv.routeinfo.RouteInfoManager#pickupTopicRouteDataorg.apache.rocketmq.namesrv.routeinfo.RouteInfoManager#topicQueueTable获取到org.apache.rocketmq.common.protocol.route.QueueData这里面存了 brokerName,再通过org.apache.rocketmq.namesrv.routeinfo.RouteInfoManager#brokerAddrTable里获取到 broker 的地址信息等,然后再获取 orderMessage 的配置。

简要分析了下 RocketMQ 的 NameServer 的代码,比较粗粒度。

0%
\ No newline at end of file diff --git a/2020/09/13/在老丈人家的小工记三/index.html b/2020/09/13/在老丈人家的小工记三/index.html index 9e8ad8b3d9..7520aa13ed 100644 --- a/2020/09/13/在老丈人家的小工记三/index.html +++ b/2020/09/13/在老丈人家的小工记三/index.html @@ -1 +1 @@ -在老丈人家的小工记三 | Nicksxs's Blog

Nicksxs's Blog

What hurts more, the pain of hard work or the pain of regret?

在老丈人家的小工记三

小工记三

前面这两周周末也都去老丈人家帮忙了,上上周周六先是去了那个在装修的旧房子那,把三楼收拾了下,因为要搬进来住,来不及等二楼装修好,就要把三楼里的东西都整理干净,这个活感觉是比较 easy,原来是就准备把三楼当放东西仓储的地方了,我们乡下大部分三层楼都是这么用的,这次也是没办法,之前搬进来的木头什么的都搬出去,主要是这上面灰尘太多,后面清理鼻孔的时候都是黑色的了,把东西都搬出去以后主要是地还是很脏,就扫了地拖了地,因为是水泥地,灰尘又太多了,拖起来都是会灰尘扬起来,整个脱完了的确干净很多,然而这会就出了个大乌龙,我们清理的是三楼的西边一间,结果老丈人上来说要住东边那间的🤦‍♂️,不过其实西边的也得清理,因为还是要放被子什么的,不算是白费功夫,接着清理东边那间,之前这个房子做过群租房,里面有个高低铺的床,当时觉得可以用在放被子什么的就没扔,只是拆掉了放旁边,我们就把它擦干净了又装好,发现螺丝🔩少了几个,亘古不变的真理,拆了以后装要不就多几个要不就少几个,不是很牢靠,不过用来放放被子省得放地上总还是可以的,对了前面还做了个事情就是铺地毯,其实也不是地毯,就是类似于墙布雨篷布那种,别人不用了送给我们的,三楼水泥地也不会铺瓷砖地板了就放一下,干净好看点,不过大小不合适要裁一下,那把剪刀是真的太难用了,我手都要抽筋了,它就是刀口只有一小个点是能剪下来的,其他都是钝的,后来还是用刀片直接裁,铺好以后,真的感觉也不太一样了,焕然一新的感觉
差不多中午了就去吃饭了,之前两次是去了一家小饭店,还是还比较干净,但是店里菜不好吃,还死贵,这次去了一家小快餐店,口味好,便宜,味道是真的不错,带鱼跟黄鱼都好吃,一点都不腥,我对这类比较腥的鱼真的是很挑剔的,基本上除了家里做的很少吃外面的,那天抱着试试的态度吃了下,真的还不错,后来丈母娘说好像这家老板是给别人结婚喜事酒席当厨师的,怪不得做的好吃,其实本来是有一点小抗拒,怕不干净什么的,后来发现菜很好吃,而且可能是老丈人跟干活的师傅去吃的比较多,老板很客气,我们吃完饭,还给我们买了葡萄吃,不过这家店有一个槽点,就是饭比较不好吃,有时候会夹生,不过后面聊起来其实是这种小菜馆饭点的通病,烧的太早太多容易多出来浪费,烧的迟了不够吃,而且大的电饭锅比较不容易烧好。
下午前面还是在处理三楼的,窗户上各种钉子,实在是太多了,我后面在走廊上排了一排🤦‍♂️,有些是直接断了,有些是就撬了出来,感觉我在杭州租房也没有这样子各种钉钉子,挂下衣服什么的也不用这么多吧,比较不能理解,搞得到处都是钉子。那天我爸也去帮忙了,主要是在卫生间里做白缝,其实也是个技术活,印象中好像我小时候自己家里也做过这个事情,但是比较模糊了,后面我们三楼搞完了就去帮我爸了,前面是我老婆二爹在那先刷上白缝,这里叫白缝,有些考究的也叫美缝,就是瓷砖铺完之后的缝,如果不去弄的话,里面水泥的颜色就露出来了,而且容易渗水,所以就要用白水泥加胶水搅拌之后糊在缝上,但是也不是直接糊,先要把缝抠一抠,因为铺瓷砖的还不会仔细到每个缝里的水泥都是一样满,而且也需要一些空间糊上去,不然就太表面的一层很容易被水直接冲掉了,然后这次其实也不是用的白水泥,而是直接现成买来就已经配好的用来填缝的,兑水搅拌均匀就好了,后面就主要是我跟我爸在搞,那个时候真的觉得我实在是太胖了,蹲下去真的没一会就受不了了,膝盖什么的太难受了,后面我跪着刷,然后膝盖又疼,也是比较不容易,不过我爸动作很快,我中间跪累了休息一会,我爸就能搞一大片,后面其实我也没做多少(谦虚一下),总体来讲这次不是很累,就是蹲着跪着腿有点受不了,是应该好好减肥了。

0%
\ No newline at end of file +在老丈人家的小工记三 | Nicksxs's Blog

Nicksxs's Blog

What hurts more, the pain of hard work or the pain of regret?

在老丈人家的小工记三

小工记三

前面这两周周末也都去老丈人家帮忙了,上上周周六先是去了那个在装修的旧房子那,把三楼收拾了下,因为要搬进来住,来不及等二楼装修好,就要把三楼里的东西都整理干净,这个活感觉是比较 easy,原来是就准备把三楼当放东西仓储的地方了,我们乡下大部分三层楼都是这么用的,这次也是没办法,之前搬进来的木头什么的都搬出去,主要是这上面灰尘太多,后面清理鼻孔的时候都是黑色的了,把东西都搬出去以后主要是地还是很脏,就扫了地拖了地,因为是水泥地,灰尘又太多了,拖起来都是会灰尘扬起来,整个脱完了的确干净很多,然而这会就出了个大乌龙,我们清理的是三楼的西边一间,结果老丈人上来说要住东边那间的🤦‍♂️,不过其实西边的也得清理,因为还是要放被子什么的,不算是白费功夫,接着清理东边那间,之前这个房子做过群租房,里面有个高低铺的床,当时觉得可以用在放被子什么的就没扔,只是拆掉了放旁边,我们就把它擦干净了又装好,发现螺丝🔩少了几个,亘古不变的真理,拆了以后装要不就多几个要不就少几个,不是很牢靠,不过用来放放被子省得放地上总还是可以的,对了前面还做了个事情就是铺地毯,其实也不是地毯,就是类似于墙布雨篷布那种,别人不用了送给我们的,三楼水泥地也不会铺瓷砖地板了就放一下,干净好看点,不过大小不合适要裁一下,那把剪刀是真的太难用了,我手都要抽筋了,它就是刀口只有一小个点是能剪下来的,其他都是钝的,后来还是用刀片直接裁,铺好以后,真的感觉也不太一样了,焕然一新的感觉
差不多中午了就去吃饭了,之前两次是去了一家小饭店,还是还比较干净,但是店里菜不好吃,还死贵,这次去了一家小快餐店,口味好,便宜,味道是真的不错,带鱼跟黄鱼都好吃,一点都不腥,我对这类比较腥的鱼真的是很挑剔的,基本上除了家里做的很少吃外面的,那天抱着试试的态度吃了下,真的还不错,后来丈母娘说好像这家老板是给别人结婚喜事酒席当厨师的,怪不得做的好吃,其实本来是有一点小抗拒,怕不干净什么的,后来发现菜很好吃,而且可能是老丈人跟干活的师傅去吃的比较多,老板很客气,我们吃完饭,还给我们买了葡萄吃,不过这家店有一个槽点,就是饭比较不好吃,有时候会夹生,不过后面聊起来其实是这种小菜馆饭点的通病,烧的太早太多容易多出来浪费,烧的迟了不够吃,而且大的电饭锅比较不容易烧好。
下午前面还是在处理三楼的,窗户上各种钉子,实在是太多了,我后面在走廊上排了一排🤦‍♂️,有些是直接断了,有些是就撬了出来,感觉我在杭州租房也没有这样子各种钉钉子,挂下衣服什么的也不用这么多吧,比较不能理解,搞得到处都是钉子。那天我爸也去帮忙了,主要是在卫生间里做白缝,其实也是个技术活,印象中好像我小时候自己家里也做过这个事情,但是比较模糊了,后面我们三楼搞完了就去帮我爸了,前面是我老婆二爹在那先刷上白缝,这里叫白缝,有些考究的也叫美缝,就是瓷砖铺完之后的缝,如果不去弄的话,里面水泥的颜色就露出来了,而且容易渗水,所以就要用白水泥加胶水搅拌之后糊在缝上,但是也不是直接糊,先要把缝抠一抠,因为铺瓷砖的还不会仔细到每个缝里的水泥都是一样满,而且也需要一些空间糊上去,不然就太表面的一层很容易被水直接冲掉了,然后这次其实也不是用的白水泥,而是直接现成买来就已经配好的用来填缝的,兑水搅拌均匀就好了,后面就主要是我跟我爸在搞,那个时候真的觉得我实在是太胖了,蹲下去真的没一会就受不了了,膝盖什么的太难受了,后面我跪着刷,然后膝盖又疼,也是比较不容易,不过我爸动作很快,我中间跪累了休息一会,我爸就能搞一大片,后面其实我也没做多少(谦虚一下),总体来讲这次不是很累,就是蹲着跪着腿有点受不了,是应该好好减肥了。

0%
\ No newline at end of file diff --git a/2020/09/26/在老丈人家的小工记四/index.html b/2020/09/26/在老丈人家的小工记四/index.html index 4c48f566b4..a48095be75 100644 --- a/2020/09/26/在老丈人家的小工记四/index.html +++ b/2020/09/26/在老丈人家的小工记四/index.html @@ -1 +1 @@ -在老丈人家的小工记四 | Nicksxs's Blog

Nicksxs's Blog

What hurts more, the pain of hard work or the pain of regret?

在老丈人家的小工记四

小工记四

第四周去的时候让我们去了现在在住的房子里,去三楼整理东西了,蛮多的东西需要收拾整理,有些需要丢一下,以前往往是把不太要用的东西就放三楼了,但是后面就不会再去收拾整理,LD 跟丈母娘负责收拾,我不太知道哪些还要的,哪些不要了,而且本来也不擅长这种收拾🤦‍♂️,然后就变成她们收拾出来废纸箱,我负责拆掉,压平,这时候终于觉得体重还算是有点作用,总体来说这个事情我其实也不擅长,不擅长的主要是捆起来,可能我总是小题大做,因为纸箱大小不一,如果不做一下分类,然后把大的折小一些的话,直接绑起来,容易拎起来就散掉了,而且一些鞋盒子这种小件的纸盒会比较薄,冰箱这种大件的比较厚,厚的比较不容易变形,需要大力踩踏,而且扎的时候需要用体重压住捆实了之后那样子才是真的捆实的,不然待会又是松松垮垮容易滑出来散架,因为压住了捆好后,下来了之后箱子就会弹开了把绳子崩紧实,感觉又是掌握到生活小技巧了😃,我这里其实比较单调无聊,然后 LD 那可以说非常厉害了,一共理出来 11 把旧电扇,还有好多没用过全新的不锈钢脸盆大大小小的,感觉比店里在卖的还多,还有是有比较多小时候的东西,特别多小时候的衣服,其实这种对我来说最难了,可能需要读一下断舍离,蛮多东西都舍不得扔,但是其实是没啥用了,然后还占地方,这天应该算是比较轻松的一天了,上午主要是把收拾出来要的和不要的搬下楼,然后下午要去把纸板给卖掉。中午还是去小快餐店吃的,在住的家里理东西还有个好处就是中午吃完饭可以小憩一下,因为我个人是非常依赖午休的,不然下午完全没精神,而且心态也会比较烦躁,一方面是客观的的确比较疲惫,另一方面应该主观心理作用也有点影响,就像上班的时候也是觉得不午睡就会很难受,心理作用也有一点,不过总之能睡还是睡一会,真的没办法就心态好点,吃完午饭之后我们就推着小平板车去收废品的地方卖掉了上午我收拾捆起来的纸板,好像卖了一百多,都是直接过地磅了,不用一捆一捆地称,不过有个小插曲,那里另外一个大爷在倒他的三轮车的时候撞了我一下,还好车速慢,屁股上肉垫后,接下来就比较麻烦了,是LD 她们两姐妹从小到大的书,也要去卖掉,小平板车就载不下了,而且着实也不太好推,轮子不太平,导致推着很累,书有好多箱,本来是想去亲戚家借电动三轮车,因为不会开摩托的那种,摩托的那种 LD 邻居家就有,可是到了那发现那个也是很大,而且刹车是用脚踩的那种,俺爹不太放心,就说第二天周日他有空会帮忙去载了卖掉的,然后比较搞笑的来了,丈母娘看错了时间,以为已经快五点了,就让我们顺便在车里带点东西去在修的房子,放到那边三楼去,到了那还跟老丈人说已经这么迟了要赶紧去菜场买菜了,结果我们回来以后才发现看错了一个小时🤦‍♂️。
前面可以没提,前三周去的我们一般就周六去一天,然后周日因为要早点回杭州,而且可能想让我们周日能休息下,但是这周就因为周日的时候我爸要去帮忙载书,然后 LD 姐姐也会过来收拾东西,我们周日就又去整理收拾了,周日由于俺爹去的很早,我过去的时候书已经木有了,主要是去收拾东西了,把一些有用没用的继续整理,基本上三楼的就处理完毕了,舒了一大口气,毕竟让丈母娘一个人收拾实在是太累了,但是要扔掉的衣服比较棘手,附近知道的青蛙回收桶被推倒了,其他地方也不知道哪里有,我们就先载了一些东西去在修的房子那,然后去找青蛙桶,结果一个小区可以进,但是已经满了,另一个不让进,后来只能让 LD 姐姐带去她们小区扔了,塞了满满一车。因为要赶回杭州的车就没有等我爸一起回来,他还在那帮忙搞卫生间的墙缝。
虽然这两天不太热,活也不算很吃力,不过我这个体重和易出汗的体质,还是让短袖不知道湿透了多少次,灌了好多水和冰红茶(下午能提提神),回来周一早上称体重也比较喜人,差一点就达到阶段目标,可以想想去哪里吃之前想好的烤肉跟火锅了(估计吃完立马回到解放前)。

0%
\ No newline at end of file +在老丈人家的小工记四 | Nicksxs's Blog

Nicksxs's Blog

What hurts more, the pain of hard work or the pain of regret?

在老丈人家的小工记四

小工记四

第四周去的时候让我们去了现在在住的房子里,去三楼整理东西了,蛮多的东西需要收拾整理,有些需要丢一下,以前往往是把不太要用的东西就放三楼了,但是后面就不会再去收拾整理,LD 跟丈母娘负责收拾,我不太知道哪些还要的,哪些不要了,而且本来也不擅长这种收拾🤦‍♂️,然后就变成她们收拾出来废纸箱,我负责拆掉,压平,这时候终于觉得体重还算是有点作用,总体来说这个事情我其实也不擅长,不擅长的主要是捆起来,可能我总是小题大做,因为纸箱大小不一,如果不做一下分类,然后把大的折小一些的话,直接绑起来,容易拎起来就散掉了,而且一些鞋盒子这种小件的纸盒会比较薄,冰箱这种大件的比较厚,厚的比较不容易变形,需要大力踩踏,而且扎的时候需要用体重压住捆实了之后那样子才是真的捆实的,不然待会又是松松垮垮容易滑出来散架,因为压住了捆好后,下来了之后箱子就会弹开了把绳子崩紧实,感觉又是掌握到生活小技巧了😃,我这里其实比较单调无聊,然后 LD 那可以说非常厉害了,一共理出来 11 把旧电扇,还有好多没用过全新的不锈钢脸盆大大小小的,感觉比店里在卖的还多,还有是有比较多小时候的东西,特别多小时候的衣服,其实这种对我来说最难了,可能需要读一下断舍离,蛮多东西都舍不得扔,但是其实是没啥用了,然后还占地方,这天应该算是比较轻松的一天了,上午主要是把收拾出来要的和不要的搬下楼,然后下午要去把纸板给卖掉。中午还是去小快餐店吃的,在住的家里理东西还有个好处就是中午吃完饭可以小憩一下,因为我个人是非常依赖午休的,不然下午完全没精神,而且心态也会比较烦躁,一方面是客观的的确比较疲惫,另一方面应该主观心理作用也有点影响,就像上班的时候也是觉得不午睡就会很难受,心理作用也有一点,不过总之能睡还是睡一会,真的没办法就心态好点,吃完午饭之后我们就推着小平板车去收废品的地方卖掉了上午我收拾捆起来的纸板,好像卖了一百多,都是直接过地磅了,不用一捆一捆地称,不过有个小插曲,那里另外一个大爷在倒他的三轮车的时候撞了我一下,还好车速慢,屁股上肉垫后,接下来就比较麻烦了,是LD 她们两姐妹从小到大的书,也要去卖掉,小平板车就载不下了,而且着实也不太好推,轮子不太平,导致推着很累,书有好多箱,本来是想去亲戚家借电动三轮车,因为不会开摩托的那种,摩托的那种 LD 邻居家就有,可是到了那发现那个也是很大,而且刹车是用脚踩的那种,俺爹不太放心,就说第二天周日他有空会帮忙去载了卖掉的,然后比较搞笑的来了,丈母娘看错了时间,以为已经快五点了,就让我们顺便在车里带点东西去在修的房子,放到那边三楼去,到了那还跟老丈人说已经这么迟了要赶紧去菜场买菜了,结果我们回来以后才发现看错了一个小时🤦‍♂️。
前面可以没提,前三周去的我们一般就周六去一天,然后周日因为要早点回杭州,而且可能想让我们周日能休息下,但是这周就因为周日的时候我爸要去帮忙载书,然后 LD 姐姐也会过来收拾东西,我们周日就又去整理收拾了,周日由于俺爹去的很早,我过去的时候书已经木有了,主要是去收拾东西了,把一些有用没用的继续整理,基本上三楼的就处理完毕了,舒了一大口气,毕竟让丈母娘一个人收拾实在是太累了,但是要扔掉的衣服比较棘手,附近知道的青蛙回收桶被推倒了,其他地方也不知道哪里有,我们就先载了一些东西去在修的房子那,然后去找青蛙桶,结果一个小区可以进,但是已经满了,另一个不让进,后来只能让 LD 姐姐带去她们小区扔了,塞了满满一车。因为要赶回杭州的车就没有等我爸一起回来,他还在那帮忙搞卫生间的墙缝。
虽然这两天不太热,活也不算很吃力,不过我这个体重和易出汗的体质,还是让短袖不知道湿透了多少次,灌了好多水和冰红茶(下午能提提神),回来周一早上称体重也比较喜人,差一点就达到阶段目标,可以想想去哪里吃之前想好的烤肉跟火锅了(估计吃完立马回到解放前)。

0%
\ No newline at end of file diff --git a/2020/10/18/在老丈人家的小工记五/index.html b/2020/10/18/在老丈人家的小工记五/index.html index 05c4df36f5..996510b0af 100644 --- a/2020/10/18/在老丈人家的小工记五/index.html +++ b/2020/10/18/在老丈人家的小工记五/index.html @@ -1 +1 @@ -在老丈人家的小工记五 | Nicksxs's Blog

Nicksxs's Blog

What hurts more, the pain of hard work or the pain of regret?

在老丈人家的小工记五

终于回忆起来了,年纪大了写这种东西真的要立马写,不然很容易想不起来,那天应该是 9 月 12 日,也就是上周六,因为我爸也去了,而且娘亲(丈母娘,LD 这么叫,我也就随了她这么叫,当然是背后,当面就叫妈)也在那,早上一到那二爹就给我爸指挥了活,要挖一条院子的出水道,自己想出来的词,因为觉得下水道是竖的,在那稍稍帮了一会会忙,然后我还是比较惯例的跟着 LD 还有娘亲去住的家里,主要是老丈人可能也不太想让我干太累的活,因为上次已经差不多把三楼都整理干净了,然后就是二楼了,二楼说实话我也帮不上什么忙,主要是衣服被子什么的,正好是有张以前小孩子睡过的那种摇篮床,看上去虽然有一些破损,整体还是不错的,所以打算拿过去,我就负责把它拆掉了,比较简单的是只要拧螺丝就行了,但是其实是用了好多好多工具才搞定的,一开始只要螺丝刀就行了,但是因为年代久了,后面的螺帽也有点锈住或者本身就会串着会一起动,所以拿来了个扳手,大部分的其实都被这两个工具给搞定了,但是后期大概还剩下四分之一的时候,有一颗完全锈住,并且螺纹跟之前那些都不一样,但是这个已经是最大的螺丝刀了,也没办法换个大的了,所以又去找来个一字的,因为十字的不是也可以用一字的拧嘛,结果可能是我买的工具箱里的一字螺丝刀太新了,口子那很锋利,直接把螺丝花纹给划掉了,大的小的都划掉,然后真的变成凹进去一个圆柱体了,然后就想能不能隔一层布去拧,然而因为的确是已经变成圆柱体了,布也不太给力,不放弃的我又去找来了个老虎钳,妄图把划掉的螺丝用老虎钳钳住,另一端用扳手拧开螺帽,但是这个螺丝跟螺帽真的是生锈的太严重了,外加上钳不太牢,完全是两边一起转,实在是没办法了,在征得同意之后,直接掰断了,火死了,一颗螺丝折腾得比我拆一张床还久,那天因为早上去的也比较晚了,然后就快吃午饭了,正好想着带一点东西过去,就把一些脸盆,泡脚桶啥的拿过去了,先是去吃了饭,还是在那家快餐店,菜的口味还是依然不错,就是人比较多,我爸旁边都是素菜,都没怎么吃远一点的荤菜,下次要早点去,把荤菜放我爸旁边😄(PS:他们家饭还是依然尴尬,需要等),吃完就开到在修的房子那把东西拿了出来,我爸已经动作很快的打了一小半的地沟了,说实话那玩意真的是很重,我之前把它从三楼拿下来,就觉得这个太重了,这次还要用起来,感觉我的手会分分钟废掉,不过一开始我还是跟着LD去了住的家里,惯例睡了午觉,那天睡得比较踏实,竟然睡了一个小时,醒了想了下,其实LD她们收拾也用不上我(没啥力气活),我还是去帮我爸他们,跟LD说了下就去了在修的老房子那,两位老爹在一起钻地,看着就很累,我连忙上去想换一会他们,因为刚好是钻到混凝土地线,特别难,力道不够就会滑开,用蛮力就是钻进去拔不出来,原理是因为本身浇的时候就是很紧实的,需要边钻边动,那家伙实在是太重了,真的是汗如雨下,基本是三个人轮流来,我是个添乱的,经常卡住,然后把地线,其实就是一条混凝土横梁,里面还有14跟18的钢筋,需要割断,这个割断也是很有技巧,钢筋本身在里面是受到挤压的,直接用切割的,到快断掉的时候就会崩一下,非常危险,还是老丈人比较有经验,要留一点点,然后直接用榔头敲断就好了,本来以为这个是最难的了,结果下面是一块非常大的青基石,而且也是石头跟石头挤一块,边上一点点打钻有点杯水车薪,后来是用那种螺旋的钻,钻四个洞,相对位置大概是个长方形,这样子把中间这个长方形钻出来就比较容易地能拿出来了,后面的也容易搞出来了,后面的其实难度不是特别大了,主要是地沟打好之后得看看高低是不是符合要求的,不能本来是往外排水的反而外面高,这个怎么看就又很有技巧了,一般在地上的只要侧着看一下就好了,考究点就用下水平尺,但是在地下的,不用水平尺,其实可以借助于地沟里正要放进去的水管,放点水进去,看水往哪流就行了,铺好水管后,就剩填埋的活了,不是太麻烦了,那天真的是累到了,打那个混凝土的时候我真的是把我整个人压上去了,不过也挺爽的,有点把平时无处发泄的蛮力发泄出去了。

0%
\ No newline at end of file +在老丈人家的小工记五 | Nicksxs's Blog

Nicksxs's Blog

What hurts more, the pain of hard work or the pain of regret?

在老丈人家的小工记五

终于回忆起来了,年纪大了写这种东西真的要立马写,不然很容易想不起来,那天应该是 9 月 12 日,也就是上周六,因为我爸也去了,而且娘亲(丈母娘,LD 这么叫,我也就随了她这么叫,当然是背后,当面就叫妈)也在那,早上一到那二爹就给我爸指挥了活,要挖一条院子的出水道,自己想出来的词,因为觉得下水道是竖的,在那稍稍帮了一会会忙,然后我还是比较惯例的跟着 LD 还有娘亲去住的家里,主要是老丈人可能也不太想让我干太累的活,因为上次已经差不多把三楼都整理干净了,然后就是二楼了,二楼说实话我也帮不上什么忙,主要是衣服被子什么的,正好是有张以前小孩子睡过的那种摇篮床,看上去虽然有一些破损,整体还是不错的,所以打算拿过去,我就负责把它拆掉了,比较简单的是只要拧螺丝就行了,但是其实是用了好多好多工具才搞定的,一开始只要螺丝刀就行了,但是因为年代久了,后面的螺帽也有点锈住或者本身就会串着会一起动,所以拿来了个扳手,大部分的其实都被这两个工具给搞定了,但是后期大概还剩下四分之一的时候,有一颗完全锈住,并且螺纹跟之前那些都不一样,但是这个已经是最大的螺丝刀了,也没办法换个大的了,所以又去找来个一字的,因为十字的不是也可以用一字的拧嘛,结果可能是我买的工具箱里的一字螺丝刀太新了,口子那很锋利,直接把螺丝花纹给划掉了,大的小的都划掉,然后真的变成凹进去一个圆柱体了,然后就想能不能隔一层布去拧,然而因为的确是已经变成圆柱体了,布也不太给力,不放弃的我又去找来了个老虎钳,妄图把划掉的螺丝用老虎钳钳住,另一端用扳手拧开螺帽,但是这个螺丝跟螺帽真的是生锈的太严重了,外加上钳不太牢,完全是两边一起转,实在是没办法了,在征得同意之后,直接掰断了,火死了,一颗螺丝折腾得比我拆一张床还久,那天因为早上去的也比较晚了,然后就快吃午饭了,正好想着带一点东西过去,就把一些脸盆,泡脚桶啥的拿过去了,先是去吃了饭,还是在那家快餐店,菜的口味还是依然不错,就是人比较多,我爸旁边都是素菜,都没怎么吃远一点的荤菜,下次要早点去,把荤菜放我爸旁边😄(PS:他们家饭还是依然尴尬,需要等),吃完就开到在修的房子那把东西拿了出来,我爸已经动作很快的打了一小半的地沟了,说实话那玩意真的是很重,我之前把它从三楼拿下来,就觉得这个太重了,这次还要用起来,感觉我的手会分分钟废掉,不过一开始我还是跟着LD去了住的家里,惯例睡了午觉,那天睡得比较踏实,竟然睡了一个小时,醒了想了下,其实LD她们收拾也用不上我(没啥力气活),我还是去帮我爸他们,跟LD说了下就去了在修的老房子那,两位老爹在一起钻地,看着就很累,我连忙上去想换一会他们,因为刚好是钻到混凝土地线,特别难,力道不够就会滑开,用蛮力就是钻进去拔不出来,原理是因为本身浇的时候就是很紧实的,需要边钻边动,那家伙实在是太重了,真的是汗如雨下,基本是三个人轮流来,我是个添乱的,经常卡住,然后把地线,其实就是一条混凝土横梁,里面还有14跟18的钢筋,需要割断,这个割断也是很有技巧,钢筋本身在里面是受到挤压的,直接用切割的,到快断掉的时候就会崩一下,非常危险,还是老丈人比较有经验,要留一点点,然后直接用榔头敲断就好了,本来以为这个是最难的了,结果下面是一块非常大的青基石,而且也是石头跟石头挤一块,边上一点点打钻有点杯水车薪,后来是用那种螺旋的钻,钻四个洞,相对位置大概是个长方形,这样子把中间这个长方形钻出来就比较容易地能拿出来了,后面的也容易搞出来了,后面的其实难度不是特别大了,主要是地沟打好之后得看看高低是不是符合要求的,不能本来是往外排水的反而外面高,这个怎么看就又很有技巧了,一般在地上的只要侧着看一下就好了,考究点就用下水平尺,但是在地下的,不用水平尺,其实可以借助于地沟里正要放进去的水管,放点水进去,看水往哪流就行了,铺好水管后,就剩填埋的活了,不是太麻烦了,那天真的是累到了,打那个混凝土的时候我真的是把我整个人压上去了,不过也挺爽的,有点把平时无处发泄的蛮力发泄出去了。

0%
\ No newline at end of file diff --git a/2021/03/28/聊聊-Linux-下的-top-命令/index.html b/2021/03/28/聊聊-Linux-下的-top-命令/index.html index d5a414ccbe..1277a8aef6 100644 --- a/2021/03/28/聊聊-Linux-下的-top-命令/index.html +++ b/2021/03/28/聊聊-Linux-下的-top-命令/index.html @@ -1,4 +1,4 @@ -聊聊 Linux 下的 top 命令 | Nicksxs's Blog

Nicksxs's Blog

What hurts more, the pain of hard work or the pain of regret?

聊聊 Linux 下的 top 命令

top 命令在日常的 Linux 使用中,特别是做一些服务器的简单状态查看,排查故障都起了比较大的作用,但是由于这个命令看到的东西比较多,一般只会看部分,或者说像我这样就会比较片面地看一些信息,比如默认是进程维度的,可以在启动命令的时候加-H进入线程模式

-H  :Threads-mode operation
+聊聊 Linux 下的 top 命令 | Nicksxs's Blog

Nicksxs's Blog

What hurts more, the pain of hard work or the pain of regret?

聊聊 Linux 下的 top 命令

top 命令在日常的 Linux 使用中,特别是做一些服务器的简单状态查看,排查故障都起了比较大的作用,但是由于这个命令看到的东西比较多,一般只会看部分,或者说像我这样就会比较片面地看一些信息,比如默认是进程维度的,可以在启动命令的时候加-H进入线程模式

-H  :Threads-mode operation
             Instructs top to display individual threads.  Without this command-line option a summation of all threads in each process  is  shown.   Later
             this can be changed with the `H' interactive command.

这样就能用在 Java 中去 jstack 中找到对应的线程
其实还有比较重要的两个操作,
一个是在 top 启动状态下,按c键,这样能把比如说是一个 Java 进程,具体的进程命令显示出来
像这样
执行前是这样

执行后是这样

第二个就是排序了

SORTING of task window
 
@@ -22,4 +22,4 @@
                  Moves the sort column to the left unless the current sort field is the first field being displayed.
 
              >  :Move-Sort-Field-Right
-                 Moves the sort column to the right unless the current sort field is the last field being displayed.

查看 man page 可以找到这一段,其实一般 man page 都是最细致的,只不过因为太多了,有时候懒得看,这里可以通过大写 M 和大写 P 分别按内存和 CPU 排序,下面还有两个小技巧,通过按 x 可以将当前活跃的排序列用不同颜色标出来,然后可以通过<>直接左右移动排序列

0%
\ No newline at end of file + Moves the sort column to the right unless the current sort field is the last field being displayed.

查看 man page 可以找到这一段,其实一般 man page 都是最细致的,只不过因为太多了,有时候懒得看,这里可以通过大写 M 和大写 P 分别按内存和 CPU 排序,下面还有两个小技巧,通过按 x 可以将当前活跃的排序列用不同颜色标出来,然后可以通过<>直接左右移动排序列

0%
\ No newline at end of file diff --git a/2021/12/05/wordpress-忘记密码的一种解决方法/index.html b/2021/12/05/wordpress-忘记密码的一种解决方法/index.html index aae8de1966..1baebbcea7 100644 --- a/2021/12/05/wordpress-忘记密码的一种解决方法/index.html +++ b/2021/12/05/wordpress-忘记密码的一种解决方法/index.html @@ -1 +1 @@ -wordpress 忘记密码的一种解决方法 | Nicksxs's Blog

Nicksxs's Blog

What hurts more, the pain of hard work or the pain of regret?

wordpress 忘记密码的一种解决方法

前阵子搭了个 WordPress,但是没怎么用,前两天发现忘了登录密码了,最近不知道是什么情况,chrome 的记住密码跟历史记录感觉有点问题,历史记录丢了不少东西,可能是时间太久了,但是理论上应该有 LRU 这种策略的,有些还比较常用,还有记住密码,因为个人域名都是用子域名分配给各个服务,有些记住了,有些又没记住密码,略蛋疼,所以就找了下这个方案。
当然这个方案不是最优的,有很多限制,首先就是要能够登陆 WordPress 的数据库,不然这个方法是没用的。
首先不管用什么方式(别违法)先登陆数据库,选择 WordPress 的数据库,可以看到里面有几个表,我们的目标就是 wp_users 表,用 select 查询看下可以看到有用户的数据,如果是像我这样搭着玩的没有创建其他用户的话应该就只有一个用户,那我们的表里的用户数据就只会有一条,当然多条的话可以通过用户名来找

然后可能我这个版本是这样,没有装额外的插件,密码只是经过了 MD5 的单向哈希,所以我们可以设定一个新密码,然后用 MD5 编码后直接更新进去

UPDATE wp_users SET user_pass = MD5('123456') WHERE ID = 1;

然后就能用自己的账户跟刚才更新的密码登录了。

0%
\ No newline at end of file +wordpress 忘记密码的一种解决方法 | Nicksxs's Blog

Nicksxs's Blog

What hurts more, the pain of hard work or the pain of regret?

wordpress 忘记密码的一种解决方法

前阵子搭了个 WordPress,但是没怎么用,前两天发现忘了登录密码了,最近不知道是什么情况,chrome 的记住密码跟历史记录感觉有点问题,历史记录丢了不少东西,可能是时间太久了,但是理论上应该有 LRU 这种策略的,有些还比较常用,还有记住密码,因为个人域名都是用子域名分配给各个服务,有些记住了,有些又没记住密码,略蛋疼,所以就找了下这个方案。
当然这个方案不是最优的,有很多限制,首先就是要能够登陆 WordPress 的数据库,不然这个方法是没用的。
首先不管用什么方式(别违法)先登陆数据库,选择 WordPress 的数据库,可以看到里面有几个表,我们的目标就是 wp_users 表,用 select 查询看下可以看到有用户的数据,如果是像我这样搭着玩的没有创建其他用户的话应该就只有一个用户,那我们的表里的用户数据就只会有一条,当然多条的话可以通过用户名来找

然后可能我这个版本是这样,没有装额外的插件,密码只是经过了 MD5 的单向哈希,所以我们可以设定一个新密码,然后用 MD5 编码后直接更新进去

UPDATE wp_users SET user_pass = MD5('123456') WHERE ID = 1;

然后就能用自己的账户跟刚才更新的密码登录了。

0%
\ No newline at end of file diff --git a/2023/02/26/分享一次折腾老旧笔记本的体验-续续篇/index.html b/2023/02/26/分享一次折腾老旧笔记本的体验-续续篇/index.html index 0f7f48a57b..a38b08ad4d 100644 --- a/2023/02/26/分享一次折腾老旧笔记本的体验-续续篇/index.html +++ b/2023/02/26/分享一次折腾老旧笔记本的体验-续续篇/index.html @@ -1 +1 @@ -分享一次折腾老旧笔记本的体验-续续篇 | Nicksxs's Blog

Nicksxs's Blog

What hurts more, the pain of hard work or the pain of regret?

分享一次折腾老旧笔记本的体验-续续篇

上周因为一些事情没回去,买好了内存条这周才回去用,结果因为不知道是 U 盘的问题还是什么原来装的那个系统起不来,然后想用之前一直用的 LD 的笔记本,结果 LD 的老笔记本也起不来了,一直卡在启动界面,猜测可能是本身也比较老了,用的机械硬盘会不会被我一直动而损坏了,所以就想搞个老毛桃跟新搞一个启动盘,结果这周最大的坑就在这了,在我的 15 寸 mbp 上用etcher做了个 win10 的启动盘,可能是分区表格式是 GUID,不是 MBR 的,老电脑不能识别,就像装个虚拟机来做启动盘,结果像老毛桃不支持这种用虚拟机的,需要本地磁盘,然后我就有用 bootcamp 安装了个 win10,又没网络,查了下网络需要用 bootcamp 下载 Windows Support 软件,下了好久一直没下完,后来又提示连不上苹果服务器,好不容易下完了,开启 win10 后,安装到一半就蓝屏了,真的是够操蛋的,在这个时候真的很需要有一个 Windows 机器的支持,LD 的那个笔记本也跟我差不多老了,虽然比较慢但之前好歹也还可以用,结果这下也被我弄坏了,家里就没有其他机器可以支持了,有点巧妇难为无米之炊的赶脚,而且还是想再折腾下我的老电脑,后面看看打算做几个 U 盘,分工职责明确,一个老毛桃的PE 盘,老毛桃的虽然不是很纯净的,但是是我一直以来用过内置工具比较全,修复启动功能比较强大的一个 pe,没用过 winpe,后续可以考虑使用下,一个 win7 的启动盘,因为是老电脑,如果后面是新的电脑可以考虑是 win10,一个 win to go 盘,这样我的 mbp 就可以直接用 win10 了,不过想来也还是要有一台 win 机器才比较好,不然很多时候都是在折腾工具,工欲善其事必先利其器,后面也可以考虑能够更深入的去了解主板的一些问题,我原来的那个主板可能是一些小的电阻等问题,如果能自己学习解决就更好了,有时候研究下还是有意思的。

0%
\ No newline at end of file +分享一次折腾老旧笔记本的体验-续续篇 | Nicksxs's Blog

Nicksxs's Blog

What hurts more, the pain of hard work or the pain of regret?

分享一次折腾老旧笔记本的体验-续续篇

上周因为一些事情没回去,买好了内存条这周才回去用,结果不知道是 U 盘的问题还是什么其他原因原来装的那个系统起不来,然后想用之前一直用的 LD 的笔记本,结果 LD 的老笔记本也起不来了,一直卡在启动界面,猜测可能是本身也比较老了,用的机械硬盘会不会被我一直动而损坏了,所以就想搞个老毛桃跟新搞一个启动盘,结果这周最大的坑就在这了,在我的 15 寸 mbp 上用etcher做了个 win10 的启动盘,可能是分区表格式是 GUID,不是 MBR 的,老电脑不能识别,就像装个虚拟机来做启动盘,结果像老毛桃不支持这种用虚拟机的,需要本地磁盘,然后我就有用 bootcamp 安装了个 win10,又没网络,查了下网络需要用 bootcamp 下载 Windows Support 软件,下了好久一直没下完,后来又提示连不上苹果服务器,好不容易下完了,开启 win10 后,安装到一半就蓝屏了,真的是够操蛋的,在这个时候真的很需要有一个 Windows 机器的支持,LD 的那个笔记本也跟我差不多老了,虽然比较慢但之前好歹也还可以用,结果这下也被我弄坏了,家里就没有其他机器可以支持了,有点巧妇难为无米之炊的赶脚,而且还是想再折腾下我的老电脑,后面看看打算做几个 U 盘,分工职责明确,一个老毛桃的PE 盘,老毛桃的虽然不是很纯净的,但是是我一直以来用过内置工具比较全,修复启动功能比较强大的一个 pe,没用过 winpe,后续可以考虑使用下,一个 win7 的启动盘,因为是老电脑,如果后面是新的电脑可以考虑是 win10,一个 win to go 盘,这样我的 mbp 就可以直接用 win10 了,不过想来也还是要有一台 win 机器才比较好,不然很多时候都是在折腾工具,工欲善其事必先利其器,后面也可以考虑能够更深入的去了解主板的一些问题,我原来的那个主板可能是一些小的电阻等问题,如果能自己学习解决就更好了,有时候研究下还是有意思的。

0%
\ No newline at end of file diff --git a/atom.xml b/atom.xml index cb8eba0ae6..29db5201fe 100644 --- a/atom.xml +++ b/atom.xml @@ -6,7 +6,7 @@ - 2023-02-26T13:52:17.750Z + 2023-03-05T11:58:14.438Z https://nicksxs.me/ @@ -21,14 +21,14 @@ https://nicksxs.me/2023/02/26/%E5%88%86%E4%BA%AB%E4%B8%80%E6%AC%A1%E6%8A%98%E8%85%BE%E8%80%81%E6%97%A7%E7%AC%94%E8%AE%B0%E6%9C%AC%E7%9A%84%E4%BD%93%E9%AA%8C-%E7%BB%AD%E7%BB%AD%E7%AF%87/ 2023-02-26T13:51:54.000Z - 2023-02-26T13:52:17.750Z + 2023-03-05T11:58:14.438Z - <p>上周因为一些事情没回去,买好了内存条这周才回去用,结果因为不知道是 U 盘的问题还是什么原来装的那个系统起不来,然后想用之前一直用的 LD 的笔记本,结果 LD + <p>上周因为一些事情没回去,买好了内存条这周才回去用,结果不知道是 U 盘的问题还是什么其他原因原来装的那个系统起不来,然后想用之前一直用的 LD 的笔记本,结果 LD diff --git a/baidusitemap.xml b/baidusitemap.xml index c729860902..f72225e4a4 100644 --- a/baidusitemap.xml +++ b/baidusitemap.xml @@ -2,7 +2,7 @@ https://nicksxs.me/2023/02/26/%E5%88%86%E4%BA%AB%E4%B8%80%E6%AC%A1%E6%8A%98%E8%85%BE%E8%80%81%E6%97%A7%E7%AC%94%E8%AE%B0%E6%9C%AC%E7%9A%84%E4%BD%93%E9%AA%8C-%E7%BB%AD%E7%BB%AD%E7%AF%87/ - 2023-02-26 + 2023-03-05 https://nicksxs.me/2023/02/19/mybatis%E7%B3%BB%E5%88%97-connection%E8%BF%9E%E6%8E%A5%E6%B1%A0%E8%A7%A3%E6%9E%90/ @@ -197,15 +197,15 @@ 2022-06-11 - https://nicksxs.me/2021/05/01/Leetcode-48-%E6%97%8B%E8%BD%AC%E5%9B%BE%E5%83%8F-Rotate-Image-%E9%A2%98%E8%A7%A3%E5%88%86%E6%9E%90/ + https://nicksxs.me/2022/03/13/Leetcode-83-%E5%88%A0%E9%99%A4%E6%8E%92%E5%BA%8F%E9%93%BE%E8%A1%A8%E4%B8%AD%E7%9A%84%E9%87%8D%E5%A4%8D%E5%85%83%E7%B4%A0-Remove-Duplicates-from-Sorted-List-Easy-%E9%A2%98%E8%A7%A3%E5%88%86%E6%9E%90/ 2022-06-11 - https://nicksxs.me/2020/08/06/Linux-%E4%B8%8B-grep-%E5%91%BD%E4%BB%A4%E7%9A%84%E4%B8%80%E7%82%B9%E5%B0%8F%E6%8A%80%E5%B7%A7/ + https://nicksxs.me/2021/05/01/Leetcode-48-%E6%97%8B%E8%BD%AC%E5%9B%BE%E5%83%8F-Rotate-Image-%E9%A2%98%E8%A7%A3%E5%88%86%E6%9E%90/ 2022-06-11 - https://nicksxs.me/2022/03/13/Leetcode-83-%E5%88%A0%E9%99%A4%E6%8E%92%E5%BA%8F%E9%93%BE%E8%A1%A8%E4%B8%AD%E7%9A%84%E9%87%8D%E5%A4%8D%E5%85%83%E7%B4%A0-Remove-Duplicates-from-Sorted-List-Easy-%E9%A2%98%E8%A7%A3%E5%88%86%E6%9E%90/ + https://nicksxs.me/2020/08/06/Linux-%E4%B8%8B-grep-%E5%91%BD%E4%BB%A4%E7%9A%84%E4%B8%80%E7%82%B9%E5%B0%8F%E6%8A%80%E5%B7%A7/ 2022-06-11 @@ -213,11 +213,11 @@ 2022-06-11 - https://nicksxs.me/2021/04/18/rust%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/ + https://nicksxs.me/2021/04/18/rust%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0-%E6%89%80%E6%9C%89%E6%9D%83%E4%BA%8C/ 2022-06-11 - https://nicksxs.me/2021/04/18/rust%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0-%E6%89%80%E6%9C%89%E6%9D%83%E4%BA%8C/ + https://nicksxs.me/2021/04/18/rust%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/ 2022-06-11 @@ -225,11 +225,11 @@ 2022-06-11 - https://nicksxs.me/2021/12/05/wordpress-%E5%BF%98%E8%AE%B0%E5%AF%86%E7%A0%81%E7%9A%84%E4%B8%80%E7%A7%8D%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95/ + https://nicksxs.me/2021/03/07/%E3%80%8A%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6%E7%AE%97%E6%B3%95%E6%89%8B%E5%86%8C%E8%AF%BB%E4%B9%A6%E3%80%8B%E7%AC%94%E8%AE%B0%E4%B9%8B%E6%95%B4%E7%90%86%E7%AE%97%E6%B3%95/ 2022-06-11 - https://nicksxs.me/2021/03/07/%E3%80%8A%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6%E7%AE%97%E6%B3%95%E6%89%8B%E5%86%8C%E8%AF%BB%E4%B9%A6%E3%80%8B%E7%AC%94%E8%AE%B0%E4%B9%8B%E6%95%B4%E7%90%86%E7%AE%97%E6%B3%95/ + https://nicksxs.me/2021/12/05/wordpress-%E5%BF%98%E8%AE%B0%E5%AF%86%E7%A0%81%E7%9A%84%E4%B8%80%E7%A7%8D%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95/ 2022-06-11 @@ -261,11 +261,11 @@ 2022-06-11 - https://nicksxs.me/2021/09/19/%E8%81%8A%E4%B8%80%E4%B8%8B-SpringBoot-%E4%B8%AD%E4%BD%BF%E7%94%A8%E7%9A%84-cglib-%E4%BD%9C%E4%B8%BA%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86%E4%B8%AD%E7%9A%84%E4%B8%80%E4%B8%AA%E6%B3%A8%E6%84%8F%E7%82%B9/ + https://nicksxs.me/2021/09/26/%E8%81%8A%E4%B8%80%E4%B8%8B-SpringBoot-%E4%B8%AD%E5%8A%A8%E6%80%81%E5%88%87%E6%8D%A2%E6%95%B0%E6%8D%AE%E6%BA%90%E7%9A%84%E6%96%B9%E6%B3%95/ 2022-06-11 - https://nicksxs.me/2021/09/26/%E8%81%8A%E4%B8%80%E4%B8%8B-SpringBoot-%E4%B8%AD%E5%8A%A8%E6%80%81%E5%88%87%E6%8D%A2%E6%95%B0%E6%8D%AE%E6%BA%90%E7%9A%84%E6%96%B9%E6%B3%95/ + https://nicksxs.me/2021/09/19/%E8%81%8A%E4%B8%80%E4%B8%8B-SpringBoot-%E4%B8%AD%E4%BD%BF%E7%94%A8%E7%9A%84-cglib-%E4%BD%9C%E4%B8%BA%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86%E4%B8%AD%E7%9A%84%E4%B8%80%E4%B8%AA%E6%B3%A8%E6%84%8F%E7%82%B9/ 2022-06-11 @@ -273,15 +273,15 @@ 2022-06-11 - https://nicksxs.me/2021/06/13/%E8%81%8A%E8%81%8A-Java-%E7%9A%84%E7%B1%BB%E5%8A%A0%E8%BD%BD%E6%9C%BA%E5%88%B6%E4%BA%8C/ + https://nicksxs.me/2021/06/27/%E8%81%8A%E8%81%8A-Java-%E4%B8%AD%E7%BB%95%E4%B8%8D%E5%BC%80%E7%9A%84-Synchronized-%E5%85%B3%E9%94%AE%E5%AD%97-%E4%BA%8C/ 2022-06-11 - https://nicksxs.me/2021/06/27/%E8%81%8A%E8%81%8A-Java-%E4%B8%AD%E7%BB%95%E4%B8%8D%E5%BC%80%E7%9A%84-Synchronized-%E5%85%B3%E9%94%AE%E5%AD%97-%E4%BA%8C/ + https://nicksxs.me/2020/08/02/%E8%81%8A%E8%81%8A-Java-%E8%87%AA%E5%B8%A6%E7%9A%84%E9%82%A3%E4%BA%9B%E9%80%86%E5%A4%A9%E5%B7%A5%E5%85%B7/ 2022-06-11 - https://nicksxs.me/2020/08/02/%E8%81%8A%E8%81%8A-Java-%E8%87%AA%E5%B8%A6%E7%9A%84%E9%82%A3%E4%BA%9B%E9%80%86%E5%A4%A9%E5%B7%A5%E5%85%B7/ + https://nicksxs.me/2021/06/13/%E8%81%8A%E8%81%8A-Java-%E7%9A%84%E7%B1%BB%E5%8A%A0%E8%BD%BD%E6%9C%BA%E5%88%B6%E4%BA%8C/ 2022-06-11 @@ -289,15 +289,15 @@ 2022-06-11 - https://nicksxs.me/2022/01/09/%E8%81%8A%E8%81%8A-Sharding-Jdbc-%E5%88%86%E5%BA%93%E5%88%86%E8%A1%A8%E4%B8%8B%E7%9A%84%E5%88%86%E9%A1%B5%E6%96%B9%E6%A1%88/ + https://nicksxs.me/2021/12/26/%E8%81%8A%E8%81%8A-Sharding-Jdbc-%E7%9A%84%E7%AE%80%E5%8D%95%E5%8E%9F%E7%90%86%E5%88%9D%E7%AF%87/ 2022-06-11 - https://nicksxs.me/2021/12/12/%E8%81%8A%E8%81%8A-Sharding-Jdbc-%E7%9A%84%E7%AE%80%E5%8D%95%E4%BD%BF%E7%94%A8/ + https://nicksxs.me/2022/01/09/%E8%81%8A%E8%81%8A-Sharding-Jdbc-%E5%88%86%E5%BA%93%E5%88%86%E8%A1%A8%E4%B8%8B%E7%9A%84%E5%88%86%E9%A1%B5%E6%96%B9%E6%A1%88/ 2022-06-11 - https://nicksxs.me/2021/12/26/%E8%81%8A%E8%81%8A-Sharding-Jdbc-%E7%9A%84%E7%AE%80%E5%8D%95%E5%8E%9F%E7%90%86%E5%88%9D%E7%AF%87/ + https://nicksxs.me/2021/12/12/%E8%81%8A%E8%81%8A-Sharding-Jdbc-%E7%9A%84%E7%AE%80%E5%8D%95%E4%BD%BF%E7%94%A8/ 2022-06-11 @@ -689,27 +689,27 @@ 2020-01-12 - https://nicksxs.me/2019/12/10/Redis-Part-1/ + https://nicksxs.me/2015/03/11/Reverse-Bits/ 2020-01-12 - https://nicksxs.me/2015/03/11/Reverse-Bits/ + https://nicksxs.me/2019/12/10/Redis-Part-1/ 2020-01-12 - https://nicksxs.me/2015/01/14/Two-Sum/ + https://nicksxs.me/2015/03/13/Reverse-Integer/ 2020-01-12 - https://nicksxs.me/2017/05/09/ambari-summary/ + https://nicksxs.me/2015/01/14/Two-Sum/ 2020-01-12 - https://nicksxs.me/2015/03/13/Reverse-Integer/ + https://nicksxs.me/2016/09/29/binary-watch/ 2020-01-12 - https://nicksxs.me/2016/09/29/binary-watch/ + https://nicksxs.me/2017/05/09/ambari-summary/ 2020-01-12 @@ -753,19 +753,19 @@ 2020-01-12 - https://nicksxs.me/2015/01/04/Path-Sum/ + https://nicksxs.me/2015/03/11/Number-Of-1-Bits/ 2020-01-12 - https://nicksxs.me/2015/03/11/Number-Of-1-Bits/ + https://nicksxs.me/2015/01/04/Path-Sum/ 2020-01-12 - https://nicksxs.me/2015/06/22/invert-binary-tree/ + https://nicksxs.me/2014/12/23/my-new-post/ 2020-01-12 - https://nicksxs.me/2014/12/23/my-new-post/ + https://nicksxs.me/2015/06/22/invert-binary-tree/ 2020-01-12 diff --git a/categories/docker/index.html b/categories/docker/index.html index 7e5b9e5b2a..3806901186 100644 --- a/categories/docker/index.html +++ b/categories/docker/index.html @@ -1 +1 @@ -分类: Docker | Nicksxs's Blog

Nicksxs's Blog

What hurts more, the pain of hard work or the pain of regret?

0%
\ No newline at end of file +分类: docker | Nicksxs's Blog

Nicksxs's Blog

What hurts more, the pain of hard work or the pain of regret?

docker 分类

2016
0%
with JavaScript enabled \ No newline at end of file diff --git a/index.html b/index.html index 24493f33ea..93f3d5002d 100644 --- a/index.html +++ b/index.html @@ -1,4 +1,4 @@ -Nicksxs's Blog - What hurts more, the pain of hard work or the pain of regret?

Nicksxs's Blog

What hurts more, the pain of hard work or the pain of regret?

上周因为一些事情没回去,买好了内存条这周才回去用,结果因为不知道是 U 盘的问题还是什么原来装的那个系统起不来,然后想用之前一直用的 LD 的笔记本,结果 LD 的老笔记本也起不来了,一直卡在启动界面,猜测可能是本身也比较老了,用的机械硬盘会不会被我一直动而损坏了,所以就想搞个老毛桃跟新搞一个启动盘,结果这周最大的坑就在这了,在我的 15 寸 mbp 上用etcher做了个 win10 的启动盘,可能是分区表格式是 GUID,不是 MBR 的,老电脑不能识别,就像装个虚拟机来做启动盘,结果像老毛桃不支持这种用虚拟机的,需要本地磁盘,然后我就有用 bootcamp 安装了个 win10,又没网络,查了下网络需要用 bootcamp 下载 Windows Support 软件,下了好久一直没下完,后来又提示连不上苹果服务器,好不容易下完了,开启 win10 后,安装到一半就蓝屏了,真的是够操蛋的,在这个时候真的很需要有一个 Windows 机器的支持,LD 的那个笔记本也跟我差不多老了,虽然比较慢但之前好歹也还可以用,结果这下也被我弄坏了,家里就没有其他机器可以支持了,有点巧妇难为无米之炊的赶脚,而且还是想再折腾下我的老电脑,后面看看打算做几个 U 盘,分工职责明确,一个老毛桃的PE 盘,老毛桃的虽然不是很纯净的,但是是我一直以来用过内置工具比较全,修复启动功能比较强大的一个 pe,没用过 winpe,后续可以考虑使用下,一个 win7 的启动盘,因为是老电脑,如果后面是新的电脑可以考虑是 win10,一个 win to go 盘,这样我的 mbp 就可以直接用 win10 了,不过想来也还是要有一台 win 机器才比较好,不然很多时候都是在折腾工具,工欲善其事必先利其器,后面也可以考虑能够更深入的去了解主板的一些问题,我原来的那个主板可能是一些小的电阻等问题,如果能自己学习解决就更好了,有时候研究下还是有意思的。

连接池主要是两个逻辑,首先是获取连接的逻辑,结合代码来讲一讲

private PooledConnection popConnection(String username, String password) throws SQLException {
+Nicksxs's Blog - What hurts more, the pain of hard work or the pain of regret?

Nicksxs's Blog

What hurts more, the pain of hard work or the pain of regret?

上周因为一些事情没回去,买好了内存条这周才回去用,结果不知道是 U 盘的问题还是什么其他原因原来装的那个系统起不来,然后想用之前一直用的 LD 的笔记本,结果 LD 的老笔记本也起不来了,一直卡在启动界面,猜测可能是本身也比较老了,用的机械硬盘会不会被我一直动而损坏了,所以就想搞个老毛桃跟新搞一个启动盘,结果这周最大的坑就在这了,在我的 15 寸 mbp 上用etcher做了个 win10 的启动盘,可能是分区表格式是 GUID,不是 MBR 的,老电脑不能识别,就像装个虚拟机来做启动盘,结果像老毛桃不支持这种用虚拟机的,需要本地磁盘,然后我就有用 bootcamp 安装了个 win10,又没网络,查了下网络需要用 bootcamp 下载 Windows Support 软件,下了好久一直没下完,后来又提示连不上苹果服务器,好不容易下完了,开启 win10 后,安装到一半就蓝屏了,真的是够操蛋的,在这个时候真的很需要有一个 Windows 机器的支持,LD 的那个笔记本也跟我差不多老了,虽然比较慢但之前好歹也还可以用,结果这下也被我弄坏了,家里就没有其他机器可以支持了,有点巧妇难为无米之炊的赶脚,而且还是想再折腾下我的老电脑,后面看看打算做几个 U 盘,分工职责明确,一个老毛桃的PE 盘,老毛桃的虽然不是很纯净的,但是是我一直以来用过内置工具比较全,修复启动功能比较强大的一个 pe,没用过 winpe,后续可以考虑使用下,一个 win7 的启动盘,因为是老电脑,如果后面是新的电脑可以考虑是 win10,一个 win to go 盘,这样我的 mbp 就可以直接用 win10 了,不过想来也还是要有一台 win 机器才比较好,不然很多时候都是在折腾工具,工欲善其事必先利其器,后面也可以考虑能够更深入的去了解主板的一些问题,我原来的那个主板可能是一些小的电阻等问题,如果能自己学习解决就更好了,有时候研究下还是有意思的。

连接池主要是两个逻辑,首先是获取连接的逻辑,结合代码来讲一讲

private PooledConnection popConnection(String username, String password) throws SQLException {
     boolean countedWait = false;
     PooledConnection conn = null;
     long t = System.currentTimeMillis();
diff --git a/leancloud.memo b/leancloud.memo
index e03019883c..5be170de82 100644
--- a/leancloud.memo
+++ b/leancloud.memo
@@ -202,4 +202,5 @@
 {"title":"分享一次折腾老旧笔记本的体验","url":"/2023/02/05/分享一次折腾老旧笔记本的体验/"},
 {"title":"分享一次折腾老旧笔记本的体验-续篇","url":"/2023/02/12/分享一次折腾老旧笔记本的体验-续篇/"},
 {"title":"mybatis系列-connection连接池解析","url":"/2023/02/19/mybatis系列-connection连接池解析/"},
+{"title":"分享一次折腾老旧笔记本的体验-续续篇","url":"/2023/02/26/分享一次折腾老旧笔记本的体验-续续篇/"},
 ]
\ No newline at end of file
diff --git a/leancloud_counter_security_urls.json b/leancloud_counter_security_urls.json
index 9dac6ea974..e4c1f6b6c5 100644
--- a/leancloud_counter_security_urls.json
+++ b/leancloud_counter_security_urls.json
@@ -1 +1 @@
-[{"title":"村上春树《1Q84》读后感","url":"/2019/12/18/1Q84读后感/"},{"title":"2019年终总结","url":"/2020/02/01/2019年终总结/"},{"title":"2020 年终总结","url":"/2021/03/31/2020-年终总结/"},{"title":"2020年中总结","url":"/2020/07/11/2020年中总结/"},{"title":"2021 年中总结","url":"/2021/07/18/2021-年中总结/"},{"title":"2021 年终总结","url":"/2022/01/22/2021-年终总结/"},{"title":"34_Search_for_a_Range","url":"/2016/08/14/34-Search-for-a-Range/"},{"title":"AQS篇二 之 Condition 浅析笔记","url":"/2021/02/21/AQS-之-Condition-浅析笔记/"},{"title":"AQS篇一","url":"/2021/02/14/AQS篇一/"},{"title":"2022 年终总结","url":"/2023/01/15/2022-年终总结/"},{"title":"add-two-number","url":"/2015/04/14/Add-Two-Number/"},{"title":"AbstractQueuedSynchronizer","url":"/2019/09/23/AbstractQueuedSynchronizer/"},{"title":"Apollo 客户端启动过程分析","url":"/2022/09/18/Apollo-客户端启动过程分析/"},{"title":"Apollo 如何获取当前环境","url":"/2022/09/04/Apollo-如何获取当前环境/"},{"title":"Clone Graph Part I","url":"/2014/12/30/Clone-Graph-Part-I/"},{"title":"Apollo 的 value 注解是怎么自动更新的","url":"/2020/11/01/Apollo-的-value-注解是怎么自动更新的/"},{"title":"Disruptor 系列一","url":"/2022/02/13/Disruptor-系列一/"},{"title":"Comparator使用小记","url":"/2020/04/05/Comparator使用小记/"},{"title":"Disruptor 系列三","url":"/2022/09/25/Disruptor-系列三/"},{"title":"Disruptor 系列二","url":"/2022/02/27/Disruptor-系列二/"},{"title":"Dubbo 使用的几个记忆点","url":"/2022/04/02/Dubbo-使用的几个记忆点/"},{"title":"Filter, Interceptor, Aop, 啥, 啥, 啥? 这些都是啥?","url":"/2020/08/22/Filter-Intercepter-Aop-啥-啥-啥-这些都是啥/"},{"title":"G1收集器概述","url":"/2020/02/09/G1收集器概述/"},{"title":"Headscale初体验以及踩坑记","url":"/2023/01/22/Headscale初体验以及踩坑记/"},{"title":"JVM源码分析之G1垃圾收集器分析一","url":"/2019/12/07/JVM-G1-Part-1/"},{"title":"Leetcode 021 合并两个有序链表 ( Merge Two Sorted Lists ) 题解分析","url":"/2021/10/07/Leetcode-021-合并两个有序链表-Merge-Two-Sorted-Lists-题解分析/"},{"title":"Leetcode 104 二叉树的最大深度(Maximum Depth of Binary Tree) 题解分析","url":"/2020/10/25/Leetcode-104-二叉树的最大深度-Maximum-Depth-of-Binary-Tree-题解分析/"},{"title":"Leetcode 053 最大子序和 ( Maximum Subarray ) 题解分析","url":"/2021/11/28/Leetcode-053-最大子序和-Maximum-Subarray-题解分析/"},{"title":"Leetcode 028 实现 strStr() ( Implement strStr() ) 题解分析","url":"/2021/10/31/Leetcode-028-实现-strStr-Implement-strStr-题解分析/"},{"title":"Leetcode 105 从前序与中序遍历序列构造二叉树(Construct Binary Tree from Preorder and Inorder Traversal) 题解分析","url":"/2020/12/13/Leetcode-105-从前序与中序遍历序列构造二叉树-Construct-Binary-Tree-from-Preorder-and-Inorder-Traversal-题解分析/"},{"title":"Leetcode 1115 交替打印 FooBar ( Print FooBar Alternately *Medium* ) 题解分析","url":"/2022/05/01/Leetcode-1115-交替打印-FooBar-Print-FooBar-Alternately-Medium-题解分析/"},{"title":"Leetcode 121 买卖股票的最佳时机(Best Time to Buy and Sell Stock) 题解分析","url":"/2021/03/14/Leetcode-121-买卖股票的最佳时机-Best-Time-to-Buy-and-Sell-Stock-题解分析/"},{"title":"Leetcode 124 二叉树中的最大路径和(Binary Tree Maximum Path Sum) 题解分析","url":"/2021/01/24/Leetcode-124-二叉树中的最大路径和-Binary-Tree-Maximum-Path-Sum-题解分析/"},{"title":"Leetcode 1260 二维网格迁移 ( Shift 2D Grid *Easy* ) 题解分析","url":"/2022/07/22/Leetcode-1260-二维网格迁移-Shift-2D-Grid-Easy-题解分析/"},{"title":"Leetcode 155 最小栈(Min Stack) 题解分析","url":"/2020/12/06/Leetcode-155-最小栈-Min-Stack-题解分析/"},{"title":"Leetcode 160 相交链表(intersection-of-two-linked-lists) 题解分析","url":"/2021/01/10/Leetcode-160-相交链表-intersection-of-two-linked-lists-题解分析/"},{"title":"Leetcode 16 最接近的三数之和 ( 3Sum Closest *Medium* ) 题解分析","url":"/2022/08/06/Leetcode-16-最接近的三数之和-3Sum-Closest-Medium-题解分析/"},{"title":"Leetcode 1862 向下取整数对和 ( Sum of Floored Pairs *Hard* ) 题解分析","url":"/2022/09/11/Leetcode-1862-向下取整数对和-Sum-of-Floored-Pairs-Hard-题解分析/"},{"title":"Leetcode 2 Add Two Numbers 题解分析","url":"/2020/10/11/Leetcode-2-Add-Two-Numbers-题解分析/"},{"title":"Leetcode 20 有效的括号 ( Valid Parentheses *Easy* ) 题解分析","url":"/2022/07/02/Leetcode-20-有效的括号-Valid-Parentheses-Easy-题解分析/"},{"title":"Leetcode 234 回文链表(Palindrome Linked List) 题解分析","url":"/2020/11/15/Leetcode-234-回文联表-Palindrome-Linked-List-题解分析/"},{"title":"Leetcode 278 第一个错误的版本 ( First Bad Version *Easy* ) 题解分析","url":"/2022/08/14/Leetcode-278-第一个错误的版本-First-Bad-Version-Easy-题解分析/"},{"title":"Leetcode 236 二叉树的最近公共祖先(Lowest Common Ancestor of a Binary Tree) 题解分析","url":"/2021/05/23/Leetcode-236-二叉树的最近公共祖先-Lowest-Common-Ancestor-of-a-Binary-Tree-题解分析/"},{"title":"Leetcode 3 Longest Substring Without Repeating Characters 题解分析","url":"/2020/09/20/Leetcode-3-Longest-Substring-Without-Repeating-Characters-题解分析/"},{"title":"Leetcode 349 两个数组的交集 ( Intersection of Two Arrays *Easy* ) 题解分析","url":"/2022/03/07/Leetcode-349-两个数组的交集-Intersection-of-Two-Arrays-Easy-题解分析/"},{"title":"Leetcode 4 寻找两个正序数组的中位数 ( Median of Two Sorted Arrays *Hard* ) 题解分析","url":"/2022/03/27/Leetcode-4-寻找两个正序数组的中位数-Median-of-Two-Sorted-Arrays-Hard-题解分析/"},{"title":"Leetcode 42 接雨水 (Trapping Rain Water) 题解分析","url":"/2021/07/04/Leetcode-42-接雨水-Trapping-Rain-Water-题解分析/"},{"title":"Leetcode 48 旋转图像(Rotate Image) 题解分析","url":"/2021/05/01/Leetcode-48-旋转图像-Rotate-Image-题解分析/"},{"title":"Leetcode 698 划分为k个相等的子集 ( Partition to K Equal Sum Subsets *Medium* ) 题解分析","url":"/2022/06/19/Leetcode-698-划分为k个相等的子集-Partition-to-K-Equal-Sum-Subsets-Medium-题解分析/"},{"title":"Leetcode 747 至少是其他数字两倍的最大数 ( Largest Number At Least Twice of Others *Easy* ) 题解分析","url":"/2022/10/02/Leetcode-747-至少是其他数字两倍的最大数-Largest-Number-At-Least-Twice-of-Others-Easy-题解分析/"},{"title":"Leetcode 885 螺旋矩阵 III ( Spiral Matrix III *Medium* ) 题解分析","url":"/2022/08/23/Leetcode-885-螺旋矩阵-III-Spiral-Matrix-III-Medium-题解分析/"},{"title":"leetcode no.3","url":"/2015/04/15/Leetcode-No-3/"},{"title":"Linux 下 grep 命令的一点小技巧","url":"/2020/08/06/Linux-下-grep-命令的一点小技巧/"},{"title":"Leetcode 83 删除排序链表中的重复元素 ( Remove Duplicates from Sorted List *Easy* ) 题解分析","url":"/2022/03/13/Leetcode-83-删除排序链表中的重复元素-Remove-Duplicates-from-Sorted-List-Easy-题解分析/"},{"title":"Path Sum","url":"/2015/01/04/Path-Sum/"},{"title":"MFC 模态对话框","url":"/2014/12/24/MFC 模态对话框/"},{"title":"Redis_分布式锁","url":"/2019/12/10/Redis-Part-1/"},{"title":"Reverse Bits","url":"/2015/03/11/Reverse-Bits/"},{"title":"Maven实用小技巧","url":"/2020/02/16/Maven实用小技巧/"},{"title":"two sum","url":"/2015/01/14/Two-Sum/"},{"title":"ambari-summary","url":"/2017/05/09/ambari-summary/"},{"title":"Reverse Integer","url":"/2015/03/13/Reverse-Integer/"},{"title":"binary-watch","url":"/2016/09/29/binary-watch/"},{"title":"docker-mysql-cluster","url":"/2016/08/14/docker-mysql-cluster/"},{"title":"Number of 1 Bits","url":"/2015/03/11/Number-Of-1-Bits/"},{"title":"docker比一般多一点的初学者介绍","url":"/2020/03/08/docker比一般多一点的初学者介绍/"},{"title":"docker比一般多一点的初学者介绍三","url":"/2020/03/21/docker比一般多一点的初学者介绍三/"},{"title":"docker比一般多一点的初学者介绍二","url":"/2020/03/15/docker比一般多一点的初学者介绍二/"},{"title":"docker比一般多一点的初学者介绍四","url":"/2022/12/25/docker比一般多一点的初学者介绍四/"},{"title":"dubbo 客户端配置的一个重要知识点","url":"/2022/06/11/dubbo-客户端配置的一个重要知识点/"},{"title":"docker使用中发现的echo命令的一个小技巧及其他","url":"/2020/03/29/echo命令的一个小技巧/"},{"title":"gogs使用webhook部署react单页应用","url":"/2020/02/22/gogs使用webhook部署react单页应用/"},{"title":"invert-binary-tree","url":"/2015/06/22/invert-binary-tree/"},{"title":"minimum-size-subarray-sum-209","url":"/2016/10/11/minimum-size-subarray-sum-209/"},{"title":"C++ 指针使用中的一个小问题","url":"/2014/12/23/my-new-post/"},{"title":"mybatis 的 foreach 使用的注意点","url":"/2022/07/09/mybatis-的-foreach-使用的注意点/"},{"title":"mybatis 的缓存是怎么回事","url":"/2020/10/03/mybatis-的缓存是怎么回事/"},{"title":"mybatis系列-mybatis是如何初始化mapper的","url":"/2022/12/04/mybatis是如何初始化mapper的/"},{"title":"mybatis 的 $ 和 # 是有啥区别","url":"/2020/09/06/mybatis-的-和-是有啥区别/"},{"title":"mybatis系列-dataSource解析","url":"/2023/01/08/mybatis系列-dataSource解析/"},{"title":"mybatis系列-typeAliases系统","url":"/2023/01/01/mybatis系列-typeAliases系统/"},{"title":"mybatis系列-入门篇","url":"/2022/11/27/mybatis系列-入门篇/"},{"title":"mybatis系列-connection连接池解析","url":"/2023/02/19/mybatis系列-connection连接池解析/"},{"title":"mybatis系列-第一条sql的更多细节","url":"/2022/12/18/mybatis系列-第一条sql的更多细节/"},{"title":"mybatis系列-第一条sql的细节","url":"/2022/12/11/mybatis系列-第一条sql的细节/"},{"title":"nginx 日志小记","url":"/2022/04/17/nginx-日志小记/"},{"title":"openresty","url":"/2019/06/18/openresty/"},{"title":"pcre-intro-and-a-simple-package","url":"/2015/01/16/pcre-intro-and-a-simple-package/"},{"title":"php-abstract-class-and-interface","url":"/2016/11/10/php-abstract-class-and-interface/"},{"title":"powershell 初体验","url":"/2022/11/13/powershell-初体验/"},{"title":"rabbitmq-tips","url":"/2017/04/25/rabbitmq-tips/"},{"title":"redis 的 rdb 和 COW 介绍","url":"/2021/08/15/redis-的-rdb-和-COW-介绍/"},{"title":"redis数据结构介绍-第一部分 SDS,链表,字典","url":"/2019/12/26/redis数据结构介绍/"},{"title":"powershell 初体验二","url":"/2022/11/20/powershell-初体验二/"},{"title":"redis数据结构介绍三-第三部分 整数集合","url":"/2020/01/10/redis数据结构介绍三/"},{"title":"redis数据结构介绍二-第二部分 跳表","url":"/2020/01/04/redis数据结构介绍二/"},{"title":"redis数据结构介绍五-第五部分 对象","url":"/2020/01/20/redis数据结构介绍五/"},{"title":"redis数据结构介绍六 快表","url":"/2020/01/22/redis数据结构介绍六/"},{"title":"redis数据结构介绍四-第四部分 压缩表","url":"/2020/01/19/redis数据结构介绍四/"},{"title":"redis淘汰策略复习","url":"/2021/08/01/redis淘汰策略复习/"},{"title":"redis系列介绍八-淘汰策略","url":"/2020/04/18/redis系列介绍八/"},{"title":"redis过期策略复习","url":"/2021/07/25/redis过期策略复习/"},{"title":"redis系列介绍七-过期策略","url":"/2020/04/12/redis系列介绍七/"},{"title":"rust学习笔记-所有权三之切片","url":"/2021/05/16/rust学习笔记-所有权三之切片/"},{"title":"rust学习笔记-所有权一","url":"/2021/04/18/rust学习笔记/"},{"title":"rust学习笔记-所有权二","url":"/2021/04/18/rust学习笔记-所有权二/"},{"title":"spark-little-tips","url":"/2017/03/28/spark-little-tips/"},{"title":"spring event 介绍","url":"/2022/01/30/spring-event-介绍/"},{"title":"summary-ranges-228","url":"/2016/10/12/summary-ranges-228/"},{"title":"swoole-websocket-test","url":"/2016/07/13/swoole-websocket-test/"},{"title":"wordpress 忘记密码的一种解决方法","url":"/2021/12/05/wordpress-忘记密码的一种解决方法/"},{"title":"《垃圾回收算法手册读书》笔记之整理算法","url":"/2021/03/07/《垃圾回收算法手册读书》笔记之整理算法/"},{"title":"一个 nginx 的简单记忆点","url":"/2022/08/21/一个-nginx-的简单记忆点/"},{"title":"上次的其他 外行聊国足","url":"/2022/03/06/上次的其他-外行聊国足/"},{"title":"介绍一下 RocketMQ","url":"/2020/06/21/介绍一下-RocketMQ/"},{"title":"《长安的荔枝》读后感","url":"/2022/07/17/《长安的荔枝》读后感/"},{"title":"介绍下最近比较实用的端口转发","url":"/2021/11/14/介绍下最近比较实用的端口转发/"},{"title":"从丁仲礼被美国制裁聊点啥","url":"/2020/12/20/从丁仲礼被美国制裁聊点啥/"},{"title":"从清华美院学姐聊聊我们身边的恶人","url":"/2020/11/29/从清华美院学姐聊聊我们身边的恶人/"},{"title":"关于读书打卡与分享","url":"/2021/02/07/关于读书打卡与分享/"},{"title":"关于公共交通再吐个槽","url":"/2021/03/21/关于公共交通再吐个槽/"},{"title":"分享一次折腾老旧笔记本的体验-续篇","url":"/2023/02/12/分享一次折腾老旧笔记本的体验-续篇/"},{"title":"分享一次折腾老旧笔记本的体验-续续篇","url":"/2023/02/26/分享一次折腾老旧笔记本的体验-续续篇/"},{"title":"分享一次折腾老旧笔记本的体验","url":"/2023/02/05/分享一次折腾老旧笔记本的体验/"},{"title":"分享一次比较诡异的 Windows 下 U盘无法退出的经历","url":"/2023/01/29/分享一次比较诡异的-Windows-下-U盘无法退出的经历/"},{"title":"分享记录一下一个 scp 操作方法","url":"/2022/02/06/分享记录一下一个-scp-操作方法/"},{"title":"周末我在老丈人家打了天小工","url":"/2020/08/16/周末我在老丈人家打了天小工/"},{"title":"在老丈人家的小工记三","url":"/2020/09/13/在老丈人家的小工记三/"},{"title":"在老丈人家的小工记五","url":"/2020/10/18/在老丈人家的小工记五/"},{"title":"寄生虫观后感","url":"/2020/03/01/寄生虫观后感/"},{"title":"屯菜惊魂记","url":"/2022/04/24/屯菜惊魂记/"},{"title":"我是如何走上跑步这条不归路的","url":"/2020/07/26/我是如何走上跑步这条不归路的/"},{"title":"搬运两个 StackOverflow 上的 Mysql 编码相关的问题解答","url":"/2022/01/16/搬运两个-StackOverflow-上的-Mysql-编码相关的问题解答/"},{"title":"是何原因竟让两人深夜奔袭十公里","url":"/2022/06/05/是何原因竟让两人深夜奔袭十公里/"},{"title":"看完了扫黑风暴,聊聊感想","url":"/2021/10/24/看完了扫黑风暴-聊聊感想/"},{"title":"给小电驴上牌","url":"/2022/03/20/给小电驴上牌/"},{"title":"分享记录一下一个 git 操作方法","url":"/2022/02/06/分享记录一下一个-git-操作方法/"},{"title":"聊一下 RocketMQ 的 DefaultMQPushConsumer 源码","url":"/2020/06/26/聊一下-RocketMQ-的-Consumer/"},{"title":"在老丈人家的小工记四","url":"/2020/09/26/在老丈人家的小工记四/"},{"title":"聊一下 RocketMQ 的 NameServer 源码","url":"/2020/07/05/聊一下-RocketMQ-的-NameServer-源码/"},{"title":"聊一下 RocketMQ 的消息存储之 MMAP","url":"/2021/09/04/聊一下-RocketMQ-的消息存储/"},{"title":"聊一下 RocketMQ 的消息存储三","url":"/2021/10/03/聊一下-RocketMQ-的消息存储三/"},{"title":"聊一下 RocketMQ 的消息存储二","url":"/2021/09/12/聊一下-RocketMQ-的消息存储二/"},{"title":"聊一下 RocketMQ 的消息存储四","url":"/2021/10/17/聊一下-RocketMQ-的消息存储四/"},{"title":"聊一下 RocketMQ 的顺序消息","url":"/2021/08/29/聊一下-RocketMQ-的顺序消息/"},{"title":"聊一下 SpringBoot 中使用的 cglib 作为动态代理中的一个注意点","url":"/2021/09/19/聊一下-SpringBoot-中使用的-cglib-作为动态代理中的一个注意点/"},{"title":"聊一下 SpringBoot 中动态切换数据源的方法","url":"/2021/09/26/聊一下-SpringBoot-中动态切换数据源的方法/"},{"title":"聊一下 SpringBoot 设置非 web 应用的方法","url":"/2022/07/31/聊一下-SpringBoot-设置非-web-应用的方法/"},{"title":"聊一下关于怎么陪伴学习","url":"/2022/11/06/聊一下关于怎么陪伴学习/"},{"title":"聊在东京奥运会闭幕式这天-二","url":"/2021/08/19/聊在东京奥运会闭幕式这天-二/"},{"title":"聊在东京奥运会闭幕式这天","url":"/2021/08/08/聊在东京奥运会闭幕式这天/"},{"title":"聊聊 Dubbo 的 SPI 续之自适应拓展","url":"/2020/06/06/聊聊-Dubbo-的-SPI-续之自适应拓展/"},{"title":"聊聊 Dubbo 的 SPI","url":"/2020/05/31/聊聊-Dubbo-的-SPI/"},{"title":"聊聊 Dubbo 的容错机制","url":"/2020/11/22/聊聊-Dubbo-的容错机制/"},{"title":"聊聊 Java 中绕不开的 Synchronized 关键字","url":"/2021/06/20/聊聊-Java-中绕不开的-Synchronized-关键字/"},{"title":"聊聊 Java 的 equals 和 hashCode 方法","url":"/2021/01/03/聊聊-Java-的-equals-和-hashCode-方法/"},{"title":"聊聊 Java 的类加载机制二","url":"/2021/06/13/聊聊-Java-的类加载机制二/"},{"title":"聊聊 Java 中绕不开的 Synchronized 关键字-二","url":"/2021/06/27/聊聊-Java-中绕不开的-Synchronized-关键字-二/"},{"title":"聊聊 Java 自带的那些*逆天*工具","url":"/2020/08/02/聊聊-Java-自带的那些逆天工具/"},{"title":"聊聊 Linux 下的 top 命令","url":"/2021/03/28/聊聊-Linux-下的-top-命令/"},{"title":"聊聊 RocketMQ 的 Broker 源码","url":"/2020/07/19/聊聊-RocketMQ-的-Broker-源码/"},{"title":"聊聊 Sharding-Jdbc 分库分表下的分页方案","url":"/2022/01/09/聊聊-Sharding-Jdbc-分库分表下的分页方案/"},{"title":"聊聊 Sharding-Jdbc 的简单使用","url":"/2021/12/12/聊聊-Sharding-Jdbc-的简单使用/"},{"title":"聊聊 Sharding-Jdbc 的简单原理初篇","url":"/2021/12/26/聊聊-Sharding-Jdbc-的简单原理初篇/"},{"title":"聊聊 dubbo 的线程池","url":"/2021/04/04/聊聊-dubbo-的线程池/"},{"title":"聊聊 mysql 的 MVCC 续篇","url":"/2020/05/02/聊聊-mysql-的-MVCC-续篇/"},{"title":"聊聊 Java 的类加载机制一","url":"/2020/11/08/聊聊-Java-的类加载机制/"},{"title":"聊聊 mysql 的 MVCC 续续篇之锁分析","url":"/2020/05/10/聊聊-mysql-的-MVCC-续续篇之加锁分析/"},{"title":"聊聊 mysql 的 MVCC","url":"/2020/04/26/聊聊-mysql-的-MVCC/"},{"title":"聊聊 mysql 索引的一些细节","url":"/2020/12/27/聊聊-mysql-索引的一些细节/"},{"title":"聊聊 redis 缓存的应用问题","url":"/2021/01/31/聊聊-redis-缓存的应用问题/"},{"title":"聊聊Java中的单例模式","url":"/2019/12/21/聊聊Java中的单例模式/"},{"title":"聊聊 SpringBoot 自动装配","url":"/2021/07/11/聊聊SpringBoot-自动装配/"},{"title":"聊聊一次 brew update 引发的血案","url":"/2020/06/13/聊聊一次-brew-update-引发的血案/"},{"title":"聊聊传说中的 ThreadLocal","url":"/2021/05/30/聊聊传说中的-ThreadLocal/"},{"title":"聊聊厦门旅游的好与不好","url":"/2021/04/11/聊聊厦门旅游的好与不好/"},{"title":"聊聊如何识别和意识到日常生活中的各类危险","url":"/2021/06/06/聊聊如何识别和意识到日常生活中的各类危险/"},{"title":"聊聊我刚学会的应用诊断方法","url":"/2020/05/22/聊聊我刚学会的应用诊断方法/"},{"title":"聊聊我理解的分布式事务","url":"/2020/05/17/聊聊我理解的分布式事务/"},{"title":"聊聊我的远程工作体验","url":"/2022/06/26/聊聊我的远程工作体验/"},{"title":"聊聊最近平淡的生活之又聊通勤","url":"/2021/11/07/聊聊最近平淡的生活/"},{"title":"聊聊最近平淡的生活之《花束般的恋爱》观后感","url":"/2021/12/31/聊聊最近平淡的生活之《花束般的恋爱》观后感/"},{"title":"聊聊最近平淡的生活之看《神探狄仁杰》","url":"/2021/12/19/聊聊最近平淡的生活之看《神探狄仁杰》/"},{"title":"聊聊最近平淡的生活之看看老剧","url":"/2021/11/21/聊聊最近平淡的生活之看看老剧/"},{"title":"聊聊给亲戚朋友的老电脑重装系统那些事儿","url":"/2021/05/09/聊聊给亲戚朋友的老电脑重装系统那些事儿/"},{"title":"聊聊这次换车牌及其他","url":"/2022/02/20/聊聊这次换车牌及其他/"},{"title":"聊聊那些加塞狗","url":"/2021/01/17/聊聊那些加塞狗/"},{"title":"聊聊部分公交车的设计bug","url":"/2021/12/05/聊聊部分公交车的设计bug/"},{"title":"记一个容器中 dubbo 注册的小知识点","url":"/2022/10/09/记一个容器中-dubbo-注册的小知识点/"},{"title":"记录下 Java Stream 的一些高效操作","url":"/2022/05/15/记录下-Java-Lambda-的一些高效操作/"},{"title":"记录下 phpunit 的入门使用方法","url":"/2022/10/16/记录下-phpunit-的入门使用方法/"},{"title":"记录下 redis 的一些使用方法","url":"/2022/10/30/记录下-redis-的一些使用方法/"},{"title":"记录下 zookeeper 集群迁移和易错点","url":"/2022/05/29/记录下-zookeeper-集群迁移/"},{"title":"重看了下《蛮荒记》说说感受","url":"/2021/10/10/重看了下《蛮荒记》说说感受/"},{"title":"这周末我又在老丈人家打了天小工","url":"/2020/08/30/这周末我又在老丈人家打了天小工/"},{"title":"记录下 phpunit 的入门使用方法之setUp和tearDown","url":"/2022/10/23/记录下-phpunit-的入门使用方法之setUp和tearDown/"},{"title":"闲聊下乘公交的用户体验","url":"/2021/02/28/闲聊下乘公交的用户体验/"},{"title":"闲话篇-也算碰到了为老不尊和坏人变老了的典型案例","url":"/2022/05/22/闲话篇-也算碰到了为老不尊和坏人变老了的典型案例/"},{"title":"闲话篇-路遇神逻辑骑车带娃爹","url":"/2022/05/08/闲话篇-路遇神逻辑骑车带娃爹/"},{"title":"难得的大扫除","url":"/2022/04/10/难得的大扫除/"}]
\ No newline at end of file
+[{"title":"2019年终总结","url":"/2020/02/01/2019年终总结/"},{"title":"村上春树《1Q84》读后感","url":"/2019/12/18/1Q84读后感/"},{"title":"2020 年终总结","url":"/2021/03/31/2020-年终总结/"},{"title":"2020年中总结","url":"/2020/07/11/2020年中总结/"},{"title":"2021 年中总结","url":"/2021/07/18/2021-年中总结/"},{"title":"2021 年终总结","url":"/2022/01/22/2021-年终总结/"},{"title":"34_Search_for_a_Range","url":"/2016/08/14/34-Search-for-a-Range/"},{"title":"AQS篇二 之 Condition 浅析笔记","url":"/2021/02/21/AQS-之-Condition-浅析笔记/"},{"title":"AQS篇一","url":"/2021/02/14/AQS篇一/"},{"title":"add-two-number","url":"/2015/04/14/Add-Two-Number/"},{"title":"AbstractQueuedSynchronizer","url":"/2019/09/23/AbstractQueuedSynchronizer/"},{"title":"Apollo 客户端启动过程分析","url":"/2022/09/18/Apollo-客户端启动过程分析/"},{"title":"Apollo 如何获取当前环境","url":"/2022/09/04/Apollo-如何获取当前环境/"},{"title":"Apollo 的 value 注解是怎么自动更新的","url":"/2020/11/01/Apollo-的-value-注解是怎么自动更新的/"},{"title":"Comparator使用小记","url":"/2020/04/05/Comparator使用小记/"},{"title":"Clone Graph Part I","url":"/2014/12/30/Clone-Graph-Part-I/"},{"title":"Disruptor 系列一","url":"/2022/02/13/Disruptor-系列一/"},{"title":"Dubbo 使用的几个记忆点","url":"/2022/04/02/Dubbo-使用的几个记忆点/"},{"title":"Disruptor 系列二","url":"/2022/02/27/Disruptor-系列二/"},{"title":"Filter, Interceptor, Aop, 啥, 啥, 啥? 这些都是啥?","url":"/2020/08/22/Filter-Intercepter-Aop-啥-啥-啥-这些都是啥/"},{"title":"G1收集器概述","url":"/2020/02/09/G1收集器概述/"},{"title":"JVM源码分析之G1垃圾收集器分析一","url":"/2019/12/07/JVM-G1-Part-1/"},{"title":"2022 年终总结","url":"/2023/01/15/2022-年终总结/"},{"title":"Leetcode 028 实现 strStr() ( Implement strStr() ) 题解分析","url":"/2021/10/31/Leetcode-028-实现-strStr-Implement-strStr-题解分析/"},{"title":"Leetcode 021 合并两个有序链表 ( Merge Two Sorted Lists ) 题解分析","url":"/2021/10/07/Leetcode-021-合并两个有序链表-Merge-Two-Sorted-Lists-题解分析/"},{"title":"Leetcode 053 最大子序和 ( Maximum Subarray ) 题解分析","url":"/2021/11/28/Leetcode-053-最大子序和-Maximum-Subarray-题解分析/"},{"title":"Leetcode 104 二叉树的最大深度(Maximum Depth of Binary Tree) 题解分析","url":"/2020/10/25/Leetcode-104-二叉树的最大深度-Maximum-Depth-of-Binary-Tree-题解分析/"},{"title":"Leetcode 105 从前序与中序遍历序列构造二叉树(Construct Binary Tree from Preorder and Inorder Traversal) 题解分析","url":"/2020/12/13/Leetcode-105-从前序与中序遍历序列构造二叉树-Construct-Binary-Tree-from-Preorder-and-Inorder-Traversal-题解分析/"},{"title":"Leetcode 1115 交替打印 FooBar ( Print FooBar Alternately *Medium* ) 题解分析","url":"/2022/05/01/Leetcode-1115-交替打印-FooBar-Print-FooBar-Alternately-Medium-题解分析/"},{"title":"Leetcode 121 买卖股票的最佳时机(Best Time to Buy and Sell Stock) 题解分析","url":"/2021/03/14/Leetcode-121-买卖股票的最佳时机-Best-Time-to-Buy-and-Sell-Stock-题解分析/"},{"title":"Disruptor 系列三","url":"/2022/09/25/Disruptor-系列三/"},{"title":"Leetcode 1260 二维网格迁移 ( Shift 2D Grid *Easy* ) 题解分析","url":"/2022/07/22/Leetcode-1260-二维网格迁移-Shift-2D-Grid-Easy-题解分析/"},{"title":"Leetcode 155 最小栈(Min Stack) 题解分析","url":"/2020/12/06/Leetcode-155-最小栈-Min-Stack-题解分析/"},{"title":"Leetcode 124 二叉树中的最大路径和(Binary Tree Maximum Path Sum) 题解分析","url":"/2021/01/24/Leetcode-124-二叉树中的最大路径和-Binary-Tree-Maximum-Path-Sum-题解分析/"},{"title":"Leetcode 16 最接近的三数之和 ( 3Sum Closest *Medium* ) 题解分析","url":"/2022/08/06/Leetcode-16-最接近的三数之和-3Sum-Closest-Medium-题解分析/"},{"title":"Leetcode 160 相交链表(intersection-of-two-linked-lists) 题解分析","url":"/2021/01/10/Leetcode-160-相交链表-intersection-of-two-linked-lists-题解分析/"},{"title":"Leetcode 1862 向下取整数对和 ( Sum of Floored Pairs *Hard* ) 题解分析","url":"/2022/09/11/Leetcode-1862-向下取整数对和-Sum-of-Floored-Pairs-Hard-题解分析/"},{"title":"Leetcode 2 Add Two Numbers 题解分析","url":"/2020/10/11/Leetcode-2-Add-Two-Numbers-题解分析/"},{"title":"Leetcode 234 回文链表(Palindrome Linked List) 题解分析","url":"/2020/11/15/Leetcode-234-回文联表-Palindrome-Linked-List-题解分析/"},{"title":"Leetcode 236 二叉树的最近公共祖先(Lowest Common Ancestor of a Binary Tree) 题解分析","url":"/2021/05/23/Leetcode-236-二叉树的最近公共祖先-Lowest-Common-Ancestor-of-a-Binary-Tree-题解分析/"},{"title":"Leetcode 20 有效的括号 ( Valid Parentheses *Easy* ) 题解分析","url":"/2022/07/02/Leetcode-20-有效的括号-Valid-Parentheses-Easy-题解分析/"},{"title":"Leetcode 3 Longest Substring Without Repeating Characters 题解分析","url":"/2020/09/20/Leetcode-3-Longest-Substring-Without-Repeating-Characters-题解分析/"},{"title":"Leetcode 278 第一个错误的版本 ( First Bad Version *Easy* ) 题解分析","url":"/2022/08/14/Leetcode-278-第一个错误的版本-First-Bad-Version-Easy-题解分析/"},{"title":"Leetcode 349 两个数组的交集 ( Intersection of Two Arrays *Easy* ) 题解分析","url":"/2022/03/07/Leetcode-349-两个数组的交集-Intersection-of-Two-Arrays-Easy-题解分析/"},{"title":"Headscale初体验以及踩坑记","url":"/2023/01/22/Headscale初体验以及踩坑记/"},{"title":"Leetcode 4 寻找两个正序数组的中位数 ( Median of Two Sorted Arrays *Hard* ) 题解分析","url":"/2022/03/27/Leetcode-4-寻找两个正序数组的中位数-Median-of-Two-Sorted-Arrays-Hard-题解分析/"},{"title":"Leetcode 42 接雨水 (Trapping Rain Water) 题解分析","url":"/2021/07/04/Leetcode-42-接雨水-Trapping-Rain-Water-题解分析/"},{"title":"Leetcode 698 划分为k个相等的子集 ( Partition to K Equal Sum Subsets *Medium* ) 题解分析","url":"/2022/06/19/Leetcode-698-划分为k个相等的子集-Partition-to-K-Equal-Sum-Subsets-Medium-题解分析/"},{"title":"Leetcode 83 删除排序链表中的重复元素 ( Remove Duplicates from Sorted List *Easy* ) 题解分析","url":"/2022/03/13/Leetcode-83-删除排序链表中的重复元素-Remove-Duplicates-from-Sorted-List-Easy-题解分析/"},{"title":"Leetcode 885 螺旋矩阵 III ( Spiral Matrix III *Medium* ) 题解分析","url":"/2022/08/23/Leetcode-885-螺旋矩阵-III-Spiral-Matrix-III-Medium-题解分析/"},{"title":"Leetcode 48 旋转图像(Rotate Image) 题解分析","url":"/2021/05/01/Leetcode-48-旋转图像-Rotate-Image-题解分析/"},{"title":"leetcode no.3","url":"/2015/04/15/Leetcode-No-3/"},{"title":"Linux 下 grep 命令的一点小技巧","url":"/2020/08/06/Linux-下-grep-命令的一点小技巧/"},{"title":"MFC 模态对话框","url":"/2014/12/24/MFC 模态对话框/"},{"title":"Number of 1 Bits","url":"/2015/03/11/Number-Of-1-Bits/"},{"title":"Maven实用小技巧","url":"/2020/02/16/Maven实用小技巧/"},{"title":"Reverse Bits","url":"/2015/03/11/Reverse-Bits/"},{"title":"Redis_分布式锁","url":"/2019/12/10/Redis-Part-1/"},{"title":"Reverse Integer","url":"/2015/03/13/Reverse-Integer/"},{"title":"Path Sum","url":"/2015/01/04/Path-Sum/"},{"title":"two sum","url":"/2015/01/14/Two-Sum/"},{"title":"binary-watch","url":"/2016/09/29/binary-watch/"},{"title":"ambari-summary","url":"/2017/05/09/ambari-summary/"},{"title":"docker-mysql-cluster","url":"/2016/08/14/docker-mysql-cluster/"},{"title":"docker比一般多一点的初学者介绍","url":"/2020/03/08/docker比一般多一点的初学者介绍/"},{"title":"docker比一般多一点的初学者介绍四","url":"/2022/12/25/docker比一般多一点的初学者介绍四/"},{"title":"docker比一般多一点的初学者介绍二","url":"/2020/03/15/docker比一般多一点的初学者介绍二/"},{"title":"dubbo 客户端配置的一个重要知识点","url":"/2022/06/11/dubbo-客户端配置的一个重要知识点/"},{"title":"docker比一般多一点的初学者介绍三","url":"/2020/03/21/docker比一般多一点的初学者介绍三/"},{"title":"gogs使用webhook部署react单页应用","url":"/2020/02/22/gogs使用webhook部署react单页应用/"},{"title":"docker使用中发现的echo命令的一个小技巧及其他","url":"/2020/03/29/echo命令的一个小技巧/"},{"title":"C++ 指针使用中的一个小问题","url":"/2014/12/23/my-new-post/"},{"title":"invert-binary-tree","url":"/2015/06/22/invert-binary-tree/"},{"title":"minimum-size-subarray-sum-209","url":"/2016/10/11/minimum-size-subarray-sum-209/"},{"title":"mybatis 的 foreach 使用的注意点","url":"/2022/07/09/mybatis-的-foreach-使用的注意点/"},{"title":"Leetcode 747 至少是其他数字两倍的最大数 ( Largest Number At Least Twice of Others *Easy* ) 题解分析","url":"/2022/10/02/Leetcode-747-至少是其他数字两倍的最大数-Largest-Number-At-Least-Twice-of-Others-Easy-题解分析/"},{"title":"mybatis 的 $ 和 # 是有啥区别","url":"/2020/09/06/mybatis-的-和-是有啥区别/"},{"title":"mybatis系列-dataSource解析","url":"/2023/01/08/mybatis系列-dataSource解析/"},{"title":"mybatis 的缓存是怎么回事","url":"/2020/10/03/mybatis-的缓存是怎么回事/"},{"title":"mybatis系列-mybatis是如何初始化mapper的","url":"/2022/12/04/mybatis是如何初始化mapper的/"},{"title":"mybatis系列-typeAliases系统","url":"/2023/01/01/mybatis系列-typeAliases系统/"},{"title":"nginx 日志小记","url":"/2022/04/17/nginx-日志小记/"},{"title":"mybatis系列-connection连接池解析","url":"/2023/02/19/mybatis系列-connection连接池解析/"},{"title":"openresty","url":"/2019/06/18/openresty/"},{"title":"pcre-intro-and-a-simple-package","url":"/2015/01/16/pcre-intro-and-a-simple-package/"},{"title":"php-abstract-class-and-interface","url":"/2016/11/10/php-abstract-class-and-interface/"},{"title":"mybatis系列-第一条sql的更多细节","url":"/2022/12/18/mybatis系列-第一条sql的更多细节/"},{"title":"mybatis系列-第一条sql的细节","url":"/2022/12/11/mybatis系列-第一条sql的细节/"},{"title":"rabbitmq-tips","url":"/2017/04/25/rabbitmq-tips/"},{"title":"mybatis系列-入门篇","url":"/2022/11/27/mybatis系列-入门篇/"},{"title":"redis数据结构介绍-第一部分 SDS,链表,字典","url":"/2019/12/26/redis数据结构介绍/"},{"title":"redis数据结构介绍三-第三部分 整数集合","url":"/2020/01/10/redis数据结构介绍三/"},{"title":"redis数据结构介绍二-第二部分 跳表","url":"/2020/01/04/redis数据结构介绍二/"},{"title":"redis 的 rdb 和 COW 介绍","url":"/2021/08/15/redis-的-rdb-和-COW-介绍/"},{"title":"redis数据结构介绍六 快表","url":"/2020/01/22/redis数据结构介绍六/"},{"title":"redis数据结构介绍四-第四部分 压缩表","url":"/2020/01/19/redis数据结构介绍四/"},{"title":"redis数据结构介绍五-第五部分 对象","url":"/2020/01/20/redis数据结构介绍五/"},{"title":"redis淘汰策略复习","url":"/2021/08/01/redis淘汰策略复习/"},{"title":"redis系列介绍七-过期策略","url":"/2020/04/12/redis系列介绍七/"},{"title":"redis过期策略复习","url":"/2021/07/25/redis过期策略复习/"},{"title":"rust学习笔记-所有权三之切片","url":"/2021/05/16/rust学习笔记-所有权三之切片/"},{"title":"rust学习笔记-所有权二","url":"/2021/04/18/rust学习笔记-所有权二/"},{"title":"redis系列介绍八-淘汰策略","url":"/2020/04/18/redis系列介绍八/"},{"title":"rust学习笔记-所有权一","url":"/2021/04/18/rust学习笔记/"},{"title":"spark-little-tips","url":"/2017/03/28/spark-little-tips/"},{"title":"spring event 介绍","url":"/2022/01/30/spring-event-介绍/"},{"title":"summary-ranges-228","url":"/2016/10/12/summary-ranges-228/"},{"title":"powershell 初体验","url":"/2022/11/13/powershell-初体验/"},{"title":"swoole-websocket-test","url":"/2016/07/13/swoole-websocket-test/"},{"title":"《垃圾回收算法手册读书》笔记之整理算法","url":"/2021/03/07/《垃圾回收算法手册读书》笔记之整理算法/"},{"title":"wordpress 忘记密码的一种解决方法","url":"/2021/12/05/wordpress-忘记密码的一种解决方法/"},{"title":"《长安的荔枝》读后感","url":"/2022/07/17/《长安的荔枝》读后感/"},{"title":"上次的其他 外行聊国足","url":"/2022/03/06/上次的其他-外行聊国足/"},{"title":"一个 nginx 的简单记忆点","url":"/2022/08/21/一个-nginx-的简单记忆点/"},{"title":"介绍一下 RocketMQ","url":"/2020/06/21/介绍一下-RocketMQ/"},{"title":"介绍下最近比较实用的端口转发","url":"/2021/11/14/介绍下最近比较实用的端口转发/"},{"title":"powershell 初体验二","url":"/2022/11/20/powershell-初体验二/"},{"title":"关于公共交通再吐个槽","url":"/2021/03/21/关于公共交通再吐个槽/"},{"title":"从清华美院学姐聊聊我们身边的恶人","url":"/2020/11/29/从清华美院学姐聊聊我们身边的恶人/"},{"title":"分享一次折腾老旧笔记本的体验-续续篇","url":"/2023/02/26/分享一次折腾老旧笔记本的体验-续续篇/"},{"title":"关于读书打卡与分享","url":"/2021/02/07/关于读书打卡与分享/"},{"title":"分享记录一下一个 git 操作方法","url":"/2022/02/06/分享记录一下一个-git-操作方法/"},{"title":"分享记录一下一个 scp 操作方法","url":"/2022/02/06/分享记录一下一个-scp-操作方法/"},{"title":"从丁仲礼被美国制裁聊点啥","url":"/2020/12/20/从丁仲礼被美国制裁聊点啥/"},{"title":"周末我在老丈人家打了天小工","url":"/2020/08/16/周末我在老丈人家打了天小工/"},{"title":"在老丈人家的小工记三","url":"/2020/09/13/在老丈人家的小工记三/"},{"title":"在老丈人家的小工记五","url":"/2020/10/18/在老丈人家的小工记五/"},{"title":"在老丈人家的小工记四","url":"/2020/09/26/在老丈人家的小工记四/"},{"title":"寄生虫观后感","url":"/2020/03/01/寄生虫观后感/"},{"title":"我是如何走上跑步这条不归路的","url":"/2020/07/26/我是如何走上跑步这条不归路的/"},{"title":"屯菜惊魂记","url":"/2022/04/24/屯菜惊魂记/"},{"title":"分享一次折腾老旧笔记本的体验-续篇","url":"/2023/02/12/分享一次折腾老旧笔记本的体验-续篇/"},{"title":"分享一次折腾老旧笔记本的体验","url":"/2023/02/05/分享一次折腾老旧笔记本的体验/"},{"title":"搬运两个 StackOverflow 上的 Mysql 编码相关的问题解答","url":"/2022/01/16/搬运两个-StackOverflow-上的-Mysql-编码相关的问题解答/"},{"title":"看完了扫黑风暴,聊聊感想","url":"/2021/10/24/看完了扫黑风暴-聊聊感想/"},{"title":"是何原因竟让两人深夜奔袭十公里","url":"/2022/06/05/是何原因竟让两人深夜奔袭十公里/"},{"title":"分享一次比较诡异的 Windows 下 U盘无法退出的经历","url":"/2023/01/29/分享一次比较诡异的-Windows-下-U盘无法退出的经历/"},{"title":"给小电驴上牌","url":"/2022/03/20/给小电驴上牌/"},{"title":"聊一下 RocketMQ 的消息存储之 MMAP","url":"/2021/09/04/聊一下-RocketMQ-的消息存储/"},{"title":"聊一下 RocketMQ 的 NameServer 源码","url":"/2020/07/05/聊一下-RocketMQ-的-NameServer-源码/"},{"title":"聊一下 RocketMQ 的 DefaultMQPushConsumer 源码","url":"/2020/06/26/聊一下-RocketMQ-的-Consumer/"},{"title":"聊一下 RocketMQ 的消息存储三","url":"/2021/10/03/聊一下-RocketMQ-的消息存储三/"},{"title":"聊一下 RocketMQ 的消息存储二","url":"/2021/09/12/聊一下-RocketMQ-的消息存储二/"},{"title":"聊一下 RocketMQ 的顺序消息","url":"/2021/08/29/聊一下-RocketMQ-的顺序消息/"},{"title":"聊一下 RocketMQ 的消息存储四","url":"/2021/10/17/聊一下-RocketMQ-的消息存储四/"},{"title":"聊一下 SpringBoot 中动态切换数据源的方法","url":"/2021/09/26/聊一下-SpringBoot-中动态切换数据源的方法/"},{"title":"聊一下 SpringBoot 设置非 web 应用的方法","url":"/2022/07/31/聊一下-SpringBoot-设置非-web-应用的方法/"},{"title":"聊一下 SpringBoot 中使用的 cglib 作为动态代理中的一个注意点","url":"/2021/09/19/聊一下-SpringBoot-中使用的-cglib-作为动态代理中的一个注意点/"},{"title":"聊聊 Dubbo 的 SPI 续之自适应拓展","url":"/2020/06/06/聊聊-Dubbo-的-SPI-续之自适应拓展/"},{"title":"聊在东京奥运会闭幕式这天-二","url":"/2021/08/19/聊在东京奥运会闭幕式这天-二/"},{"title":"聊在东京奥运会闭幕式这天","url":"/2021/08/08/聊在东京奥运会闭幕式这天/"},{"title":"聊聊 Dubbo 的容错机制","url":"/2020/11/22/聊聊-Dubbo-的容错机制/"},{"title":"聊聊 Java 中绕不开的 Synchronized 关键字-二","url":"/2021/06/27/聊聊-Java-中绕不开的-Synchronized-关键字-二/"},{"title":"聊聊 Dubbo 的 SPI","url":"/2020/05/31/聊聊-Dubbo-的-SPI/"},{"title":"聊聊 Java 的 equals 和 hashCode 方法","url":"/2021/01/03/聊聊-Java-的-equals-和-hashCode-方法/"},{"title":"聊聊 Java 的类加载机制一","url":"/2020/11/08/聊聊-Java-的类加载机制/"},{"title":"聊聊 Java 中绕不开的 Synchronized 关键字","url":"/2021/06/20/聊聊-Java-中绕不开的-Synchronized-关键字/"},{"title":"聊聊 Java 自带的那些*逆天*工具","url":"/2020/08/02/聊聊-Java-自带的那些逆天工具/"},{"title":"聊聊 Java 的类加载机制二","url":"/2021/06/13/聊聊-Java-的类加载机制二/"},{"title":"聊聊 Linux 下的 top 命令","url":"/2021/03/28/聊聊-Linux-下的-top-命令/"},{"title":"聊聊 RocketMQ 的 Broker 源码","url":"/2020/07/19/聊聊-RocketMQ-的-Broker-源码/"},{"title":"聊聊 Sharding-Jdbc 的简单原理初篇","url":"/2021/12/26/聊聊-Sharding-Jdbc-的简单原理初篇/"},{"title":"聊聊 Sharding-Jdbc 分库分表下的分页方案","url":"/2022/01/09/聊聊-Sharding-Jdbc-分库分表下的分页方案/"},{"title":"聊聊 Sharding-Jdbc 的简单使用","url":"/2021/12/12/聊聊-Sharding-Jdbc-的简单使用/"},{"title":"聊聊 dubbo 的线程池","url":"/2021/04/04/聊聊-dubbo-的线程池/"},{"title":"聊聊 mysql 的 MVCC","url":"/2020/04/26/聊聊-mysql-的-MVCC/"},{"title":"聊聊 mysql 的 MVCC 续续篇之锁分析","url":"/2020/05/10/聊聊-mysql-的-MVCC-续续篇之加锁分析/"},{"title":"聊聊 mysql 的 MVCC 续篇","url":"/2020/05/02/聊聊-mysql-的-MVCC-续篇/"},{"title":"聊聊 mysql 索引的一些细节","url":"/2020/12/27/聊聊-mysql-索引的一些细节/"},{"title":"聊聊 redis 缓存的应用问题","url":"/2021/01/31/聊聊-redis-缓存的应用问题/"},{"title":"聊聊Java中的单例模式","url":"/2019/12/21/聊聊Java中的单例模式/"},{"title":"聊聊一次 brew update 引发的血案","url":"/2020/06/13/聊聊一次-brew-update-引发的血案/"},{"title":"聊聊传说中的 ThreadLocal","url":"/2021/05/30/聊聊传说中的-ThreadLocal/"},{"title":"聊聊 SpringBoot 自动装配","url":"/2021/07/11/聊聊SpringBoot-自动装配/"},{"title":"聊聊厦门旅游的好与不好","url":"/2021/04/11/聊聊厦门旅游的好与不好/"},{"title":"聊聊如何识别和意识到日常生活中的各类危险","url":"/2021/06/06/聊聊如何识别和意识到日常生活中的各类危险/"},{"title":"聊一下关于怎么陪伴学习","url":"/2022/11/06/聊一下关于怎么陪伴学习/"},{"title":"聊聊我的远程工作体验","url":"/2022/06/26/聊聊我的远程工作体验/"},{"title":"聊聊我理解的分布式事务","url":"/2020/05/17/聊聊我理解的分布式事务/"},{"title":"聊聊最近平淡的生活之《花束般的恋爱》观后感","url":"/2021/12/31/聊聊最近平淡的生活之《花束般的恋爱》观后感/"},{"title":"聊聊最近平淡的生活之又聊通勤","url":"/2021/11/07/聊聊最近平淡的生活/"},{"title":"聊聊我刚学会的应用诊断方法","url":"/2020/05/22/聊聊我刚学会的应用诊断方法/"},{"title":"聊聊最近平淡的生活之看看老剧","url":"/2021/11/21/聊聊最近平淡的生活之看看老剧/"},{"title":"聊聊最近平淡的生活之看《神探狄仁杰》","url":"/2021/12/19/聊聊最近平淡的生活之看《神探狄仁杰》/"},{"title":"聊聊部分公交车的设计bug","url":"/2021/12/05/聊聊部分公交车的设计bug/"},{"title":"聊聊那些加塞狗","url":"/2021/01/17/聊聊那些加塞狗/"},{"title":"聊聊给亲戚朋友的老电脑重装系统那些事儿","url":"/2021/05/09/聊聊给亲戚朋友的老电脑重装系统那些事儿/"},{"title":"聊聊这次换车牌及其他","url":"/2022/02/20/聊聊这次换车牌及其他/"},{"title":"记录下 Java Stream 的一些高效操作","url":"/2022/05/15/记录下-Java-Lambda-的一些高效操作/"},{"title":"记录下 phpunit 的入门使用方法之setUp和tearDown","url":"/2022/10/23/记录下-phpunit-的入门使用方法之setUp和tearDown/"},{"title":"记录下 zookeeper 集群迁移和易错点","url":"/2022/05/29/记录下-zookeeper-集群迁移/"},{"title":"这周末我又在老丈人家打了天小工","url":"/2020/08/30/这周末我又在老丈人家打了天小工/"},{"title":"重看了下《蛮荒记》说说感受","url":"/2021/10/10/重看了下《蛮荒记》说说感受/"},{"title":"闲聊下乘公交的用户体验","url":"/2021/02/28/闲聊下乘公交的用户体验/"},{"title":"闲话篇-也算碰到了为老不尊和坏人变老了的典型案例","url":"/2022/05/22/闲话篇-也算碰到了为老不尊和坏人变老了的典型案例/"},{"title":"记一个容器中 dubbo 注册的小知识点","url":"/2022/10/09/记一个容器中-dubbo-注册的小知识点/"},{"title":"闲话篇-路遇神逻辑骑车带娃爹","url":"/2022/05/08/闲话篇-路遇神逻辑骑车带娃爹/"},{"title":"难得的大扫除","url":"/2022/04/10/难得的大扫除/"},{"title":"记录下 redis 的一些使用方法","url":"/2022/10/30/记录下-redis-的一些使用方法/"},{"title":"记录下 phpunit 的入门使用方法","url":"/2022/10/16/记录下-phpunit-的入门使用方法/"}]
\ No newline at end of file
diff --git a/search.xml b/search.xml
index e5895a123b..e9c38f295a 100644
--- a/search.xml
+++ b/search.xml
@@ -1,25 +1,5 @@
 
 
-  
-    村上春树《1Q84》读后感
-    /2019/12/18/1Q84%E8%AF%BB%E5%90%8E%E6%84%9F/
-    看完了村上春树的《1Q84》,这应该是第五本看的他的书了,继 跑步,挪威的森林,刺杀骑士团长,海边的卡夫卡之后,不是其中最长的,好像是海边的卡夫卡还是刺杀骑士团长比较长一点,都是在微信读书上看的,比较方便,最开始在上面看的是高晓松的《鱼羊野史》,不知道为啥取这个名字,但是还是满吸引我的,不过由于去年的种种,没有很多心思把它看完,而且本身的组织形式就是比较松散的,看到哪算哪,其实一些野史部分是我比较喜欢,有些谈到人物的就不太有兴趣,而且类似于大祥哥吃的东西,反正都是哇,怎么这么好吃,嗯,太爱(niu)你(bi)了,高晓松就是这个人是我最喜欢的 xxx 家,我也没去细究过他有没有说重复过,反正是不太爱,后来因为这书还一度对战争史有了浓厚的兴趣,然而事实告诉我,大部头的战争史,其实正史我是真的啃不下去,我可能只对其中 10%的内容感兴趣,不过终于也在今年把它看完了,好像高晓松的晓说也最终季了,貌似其中讲朝鲜战争的还被和谐了,看样子是说出了一些故事(truth)。

-

本来只是想把 《1Q84》的读后感写下,现在觉得还是把这篇当成我今年的读书总结吧,不过先从《1Q84》说起。

-

严格来讲,这不是很书面化的读后感,可能我想写的也只是像聊天一样的说下我读过的书,包括的技术博客其实也是类似的,以后或许会转变,但是目前水平如此吧,写多了可能会变好,也可能不会。

-

开始正文吧,这书有点类似于海边的卡夫卡,一开始是通过两条故事线,穿插着叙述,一条是青豆的,不算是个职业杀手的女杀手,要去解决一个经常家暴的斯文败类,穿着描述得比较性感吧,杀人方式是通过比较长的细针,从脖子后面一个精巧的位置插入,可以造成是未知原因死亡的假象,可能会推断成心梗之类的,这里有个前置的细节,就是青豆是乘坐一辆很高级的出租车,内饰什么的都非常有质感,有点不像一辆出租车,然后车里放了一首比较小众的歌,雅纳切克的《小交响曲》,但是青豆知道它,这跟后面的情节也有些许关系,这是女主人公青豆的出场;相应的男主的出场印象不是太深刻,男主叫天吾,是个不知名的作家,跟一个叫小松的编辑有比较好的关系,虽然天吾还没有拿到比较有分量的奖项,但是小松很看好他,也让他帮忙审校一个新作家奖的投稿文章,虽然天吾自身还没获得过这个奖,天吾还有个正式工作,是当数学老师,天吾在学生时代是个数学天才,但后面有对文学产生了兴趣,文学还不足以养活自己,靠着教课还是能保持温饱;

-

接下来是正式故事的起点了,就是小松收到了一部小说投稿,名叫《空气蛹》,是个叫深绘里的女孩子投的稿,小松对他赋予了很高的评价,这里好像记岔了,好像是天吾对这部小说很有好感,但是小松比较怀疑,然后小松看了之后也有了浓厚的兴趣,这里就是开端了,小松想让天吾来重写润色这部《空气蛹》,因为故事本身很有分量,但是描写手法叙事方式等都很拙劣,而天吾正好擅长这个,小松对天吾的评价是,描写技巧无可挑剔,就是故事主体的火花还没际遇迸发,需要一个导火索,这个就可以类比我们程序员,很多比较初中级的程序员主要擅长在原来的代码上修修改改或者给他分配个小功能,比较高级的程序员就需要能做一些项目的架构设计,核心的技术方案设计,以前我也觉得写文档这个比较无聊,但是当一个项目真的比较庞大,复杂的时候,整体和核心部分的架构设计和方案还是需要有文档沉淀的,不然别人不知道没法接受,自己过段时间也会忘记。

-

对于小松的这个建议,他的初衷是想搅一搅这个死气沉沉套路颇深的文坛,因为本身《空气蛹》这部小说的内容很吸引人,小松想通过天吾的润色补充让这部小说冲击新人奖,有种恶作剧的意图,天吾对此表示很多担心和顾虑,小松的这个建议其实也是一种文学作假,有两方面的担心,一方面是原作者深绘里是否同意如此操作,一方面是外界如果发现了这个事实会有什么样的后果,但是小松表示不用担心,前一步由小松牵线,让天吾跟原作者深绘里当面沟通这个代写是否被允许,结果当然是被允许了,这里有了对深绘里的初步描写,按我的理解是比较仙的感觉,然后语言沟通有些吃力,或者说有她自己的特色,当面沟通时貌似是让深绘里回去再考虑下,然后后面再由天吾去深绘里寄宿的戎野老师家沟通具体的细节。

-

2019年12月18日23:37:19 更新
去到戎野老师家之后,天吾知道了关于深绘里的一些事情,深绘里的父亲与戎野老师应该是老友,深绘里的父亲在当初成立了一个叫”先驱”的公社,一个独立运行的社会组织,以运营农场作为物资来源,追求更为松散的共同体,即不过分激进地公有制,进行松散的共同生活,承认私有财产,简而言之就是这样一个能稳定存活下来的独立社会组织,但是随着稳定运行,内部的激进派和稳健派开始出现分歧,不可磨合,后来两派就分裂了,深绘里的父亲,深田保留在了稳健派,但是此时其实深田保内心是矛盾的,以为一开始其实是他倡导的独立革命才组织起了这群人,然而现在他又认清了现实社会已经不太相信能通过革命来独立的可能性,后来激进派便开始越加封闭,而且进行军事训练和思想教育,而后这个先驱的激进派别便有了新的名字”黎明”,深绘里也是在此时从先驱逃离来投靠戎野老师
暂时先写到这,未完待续~

-]]>
- - 生活 - 读后感 - 村上春树 - - - 读后感 - -
2019年终总结 /2020/02/01/2019%E5%B9%B4%E7%BB%88%E6%80%BB%E7%BB%93/ @@ -49,6 +29,26 @@ 2019 + + 村上春树《1Q84》读后感 + /2019/12/18/1Q84%E8%AF%BB%E5%90%8E%E6%84%9F/ + 看完了村上春树的《1Q84》,这应该是第五本看的他的书了,继 跑步,挪威的森林,刺杀骑士团长,海边的卡夫卡之后,不是其中最长的,好像是海边的卡夫卡还是刺杀骑士团长比较长一点,都是在微信读书上看的,比较方便,最开始在上面看的是高晓松的《鱼羊野史》,不知道为啥取这个名字,但是还是满吸引我的,不过由于去年的种种,没有很多心思把它看完,而且本身的组织形式就是比较松散的,看到哪算哪,其实一些野史部分是我比较喜欢,有些谈到人物的就不太有兴趣,而且类似于大祥哥吃的东西,反正都是哇,怎么这么好吃,嗯,太爱(niu)你(bi)了,高晓松就是这个人是我最喜欢的 xxx 家,我也没去细究过他有没有说重复过,反正是不太爱,后来因为这书还一度对战争史有了浓厚的兴趣,然而事实告诉我,大部头的战争史,其实正史我是真的啃不下去,我可能只对其中 10%的内容感兴趣,不过终于也在今年把它看完了,好像高晓松的晓说也最终季了,貌似其中讲朝鲜战争的还被和谐了,看样子是说出了一些故事(truth)。

+

本来只是想把 《1Q84》的读后感写下,现在觉得还是把这篇当成我今年的读书总结吧,不过先从《1Q84》说起。

+

严格来讲,这不是很书面化的读后感,可能我想写的也只是像聊天一样的说下我读过的书,包括的技术博客其实也是类似的,以后或许会转变,但是目前水平如此吧,写多了可能会变好,也可能不会。

+

开始正文吧,这书有点类似于海边的卡夫卡,一开始是通过两条故事线,穿插着叙述,一条是青豆的,不算是个职业杀手的女杀手,要去解决一个经常家暴的斯文败类,穿着描述得比较性感吧,杀人方式是通过比较长的细针,从脖子后面一个精巧的位置插入,可以造成是未知原因死亡的假象,可能会推断成心梗之类的,这里有个前置的细节,就是青豆是乘坐一辆很高级的出租车,内饰什么的都非常有质感,有点不像一辆出租车,然后车里放了一首比较小众的歌,雅纳切克的《小交响曲》,但是青豆知道它,这跟后面的情节也有些许关系,这是女主人公青豆的出场;相应的男主的出场印象不是太深刻,男主叫天吾,是个不知名的作家,跟一个叫小松的编辑有比较好的关系,虽然天吾还没有拿到比较有分量的奖项,但是小松很看好他,也让他帮忙审校一个新作家奖的投稿文章,虽然天吾自身还没获得过这个奖,天吾还有个正式工作,是当数学老师,天吾在学生时代是个数学天才,但后面有对文学产生了兴趣,文学还不足以养活自己,靠着教课还是能保持温饱;

+

接下来是正式故事的起点了,就是小松收到了一部小说投稿,名叫《空气蛹》,是个叫深绘里的女孩子投的稿,小松对他赋予了很高的评价,这里好像记岔了,好像是天吾对这部小说很有好感,但是小松比较怀疑,然后小松看了之后也有了浓厚的兴趣,这里就是开端了,小松想让天吾来重写润色这部《空气蛹》,因为故事本身很有分量,但是描写手法叙事方式等都很拙劣,而天吾正好擅长这个,小松对天吾的评价是,描写技巧无可挑剔,就是故事主体的火花还没际遇迸发,需要一个导火索,这个就可以类比我们程序员,很多比较初中级的程序员主要擅长在原来的代码上修修改改或者给他分配个小功能,比较高级的程序员就需要能做一些项目的架构设计,核心的技术方案设计,以前我也觉得写文档这个比较无聊,但是当一个项目真的比较庞大,复杂的时候,整体和核心部分的架构设计和方案还是需要有文档沉淀的,不然别人不知道没法接受,自己过段时间也会忘记。

+

对于小松的这个建议,他的初衷是想搅一搅这个死气沉沉套路颇深的文坛,因为本身《空气蛹》这部小说的内容很吸引人,小松想通过天吾的润色补充让这部小说冲击新人奖,有种恶作剧的意图,天吾对此表示很多担心和顾虑,小松的这个建议其实也是一种文学作假,有两方面的担心,一方面是原作者深绘里是否同意如此操作,一方面是外界如果发现了这个事实会有什么样的后果,但是小松表示不用担心,前一步由小松牵线,让天吾跟原作者深绘里当面沟通这个代写是否被允许,结果当然是被允许了,这里有了对深绘里的初步描写,按我的理解是比较仙的感觉,然后语言沟通有些吃力,或者说有她自己的特色,当面沟通时貌似是让深绘里回去再考虑下,然后后面再由天吾去深绘里寄宿的戎野老师家沟通具体的细节。

+

2019年12月18日23:37:19 更新
去到戎野老师家之后,天吾知道了关于深绘里的一些事情,深绘里的父亲与戎野老师应该是老友,深绘里的父亲在当初成立了一个叫”先驱”的公社,一个独立运行的社会组织,以运营农场作为物资来源,追求更为松散的共同体,即不过分激进地公有制,进行松散的共同生活,承认私有财产,简而言之就是这样一个能稳定存活下来的独立社会组织,但是随着稳定运行,内部的激进派和稳健派开始出现分歧,不可磨合,后来两派就分裂了,深绘里的父亲,深田保留在了稳健派,但是此时其实深田保内心是矛盾的,以为一开始其实是他倡导的独立革命才组织起了这群人,然而现在他又认清了现实社会已经不太相信能通过革命来独立的可能性,后来激进派便开始越加封闭,而且进行军事训练和思想教育,而后这个先驱的激进派别便有了新的名字”黎明”,深绘里也是在此时从先驱逃离来投靠戎野老师
暂时先写到这,未完待续~

+]]>
+ + 生活 + 读后感 + 村上春树 + + + 读后感 + +
2020 年终总结 /2021/03/31/2020-%E5%B9%B4%E7%BB%88%E6%80%BB%E7%BB%93/ @@ -904,22 +904,6 @@ public: aqs - - 2022 年终总结 - /2023/01/15/2022-%E5%B9%B4%E7%BB%88%E6%80%BB%E7%BB%93/ - 一年又一年,时间匆匆,这一年过得不太容易,很多事情都是来得猝不及防,很多规划也照例是没有完成,今年更多了一些,又是比较丧的一篇总结
工作上的变化让我多理解了一些社会跟职场的现实吧,可能的确是我不够优秀,也可能是其他,说回我自身,在工作中今年应该是收获比较一般的一年,不能说没有,对原先不熟悉的业务的掌握程度有了比较大的提升,只是问题依旧存在,也挺难推动完全改变,只能尽自己所能,而这一点也主要是在团队中的定位因为前面说的一些原因,在前期不明确,限制比较大,虽然现在并没有完全解决,但也有了一些明显的改善,如果明年继续为这家公司服务,希望能有所突破,在人心沟通上的技巧总是比较反感,可也是不得不使用或者说被迫学习使用的,LD说我的对错观太强了,拗不过来,希望能有所改变。
长远的规划上没有什么明确的想法,很容易否定原来的各种想法,见识过各种现实的残酷,明白以前的一些想法不够全面或者比较幼稚,想有更上一层楼的机会,只是不希望是通过自己不认可的方式。比较能接受的是通过提升自己的技术和执行力,能够有更进一步的可能。
技术上是挺失败的去年跟前年还是能看一些书,学一些东西,今年少了很多,可能对原来比较熟悉的都有些遗忘,最近有在改善博客的内容,能更多的是系列化的,由浅入深,只是还很不完善,没什么规划,体系上也还不完整,不过还是以mybatis作为一个开头,后续新开始的内容或者原先写过的相关的都能做个整理,不再是想到啥就写点啥。最近的一个重点是在k8s上,学习方式跟一些特别优秀的人比起来还是会慢一些,不过也是自己的方法,能够更深入的理解整个体系,并讲解出来,可能会尝试采用视频的方式,对一些比较好的内容做尝试,看看会不会有比较好的数据和反馈,在22年还苟着周更的独立技术博客也算是比较稀有了的,其他站的发布也要勤一些,形成所谓的“矩阵”。
跑步减肥这个么还是比较惨,22年只跑了368公里,比21年少了85公里,有一些客观但很多是主观的原因,还是需要跑起来,只是减肥也很迫切,体重比较大跑步还是有些压力的,买了动感单车,就是时间稍长屁股痛这个目前比较难解决,骑还是每天在骑就是强度跟时间不太够,要保证每天30分钟的量可能会比较好。
加油吧,愿23年家人和自己都健康,顺遂。大家也一样。

-]]>
- - 生活 - 年终总结 - - - 生活 - 年终总结 - 2022 - 2023 - -
add-two-number /2015/04/14/Add-Two-Number/ @@ -1475,59 +1459,6 @@ public: environment - - Clone Graph Part I - /2014/12/30/Clone-Graph-Part-I/ - problem
Clone a graph. Input is a Node pointer. Return the Node pointer of the cloned graph.
-
-A graph is defined below:
-struct Node {
-vector neighbors;
-}
- - -

code

typedef unordered_map<Node *, Node *> Map;
- 
-Node *clone(Node *graph) {
-    if (!graph) return NULL;
- 
-    Map map;
-    queue<Node *> q;
-    q.push(graph);
- 
-    Node *graphCopy = new Node();
-    map[graph] = graphCopy;
- 
-    while (!q.empty()) {
-        Node *node = q.front();
-        q.pop();
-        int n = node->neighbors.size();
-        for (int i = 0; i < n; i++) {
-            Node *neighbor = node->neighbors[i];
-            // no copy exists
-            if (map.find(neighbor) == map.end()) {
-                Node *p = new Node();
-                map[node]->neighbors.push_back(p);
-                map[neighbor] = p;
-                q.push(neighbor);
-            } else {     // a copy already exists
-                map[node]->neighbors.push_back(map[neighbor]);
-            }
-        }
-    }
- 
-    return graphCopy;
-}
-

anlysis

using the Breadth-first traversal
and use a map to save the neighbors not to be duplicated.

-]]>
- - leetcode - - - C++ - leetcode - -
Apollo 的 value 注解是怎么自动更新的 /2020/11/01/Apollo-%E7%9A%84-value-%E6%B3%A8%E8%A7%A3%E6%98%AF%E6%80%8E%E4%B9%88%E8%87%AA%E5%8A%A8%E6%9B%B4%E6%96%B0%E7%9A%84/ @@ -1615,95 +1546,6 @@ Node *clone(Node *graph) { 注解 - - Disruptor 系列一 - /2022/02/13/Disruptor-%E7%B3%BB%E5%88%97%E4%B8%80/ - 很久之前就听说过这个框架,不过之前有点跟消息队列混起来,这个也是种队列,但不是跟 rocketmq,nsq 那种一样的,而是在进程内部提供队列服务的,偏向于取代ArrayBlockingQueue,因为这个阻塞队列是使用了锁来控制阻塞,关于并发其实有一些通用的最佳实践,就是用锁,即使是 JDK 提供的锁,也是比较耗资源的,当然这是跟不加锁的对比,同样是锁,JDK 的实现还是性能比较优秀的。常见的阻塞队列中例如 ArrayBlockingQueueLinkedBlockingQueue 都有锁的身影的存在,区别在于 ArrayBlockingQueue 是一把锁,后者是两把锁,不过重点不在几把锁,这里其实是两个问题,一个是所谓的 lock free, 对于一个单生产者的 disruptor 来说,因为写入是只有一个线程的,是可以不用加锁,多生产者的时候使用的是 cas 来获取对应的写入坑位,另一个是解决“伪共享”问题,后面可以详细点分析,先介绍下使用
首先是数据源

-
public class LongEvent {
-    private long value;
-
-    public void set(long value) {
-        this.value = value;
-    }
-
-    public long getValue() {
-        return value;
-    }
-
-    public void setValue(long value) {
-        this.value = value;
-    }
-}
-

事件生产

-
public class LongEventFactory implements EventFactory<LongEvent>
-{
-    public LongEvent newInstance()
-    {
-        return new LongEvent();
-    }
-}
-

事件处理器

-
public class LongEventHandler implements EventHandler<LongEvent> {
-
-    // event 事件,
-    // sequence 当前的序列 
-    // 是否当前批次最后一个数据
-    public void onEvent(LongEvent event, long sequence, boolean endOfBatch)
-    {
-        String str = String.format("long event : %s l:%s b:%s", event.getValue(), sequence, endOfBatch);
-        System.out.println(str);
-    }
-}
-
-

主方法代码

-
package disruptor;
-
-import com.lmax.disruptor.RingBuffer;
-import com.lmax.disruptor.dsl.Disruptor;
-import com.lmax.disruptor.util.DaemonThreadFactory;
-
-import java.nio.ByteBuffer;
-
-public class LongEventMain
-{
-    public static void main(String[] args) throws Exception
-    {
-        // 这个需要是 2 的幂次,这样在定位的时候只需要位移操作,也能减少各种计算操作
-        int bufferSize = 1024; 
-
-        Disruptor<LongEvent> disruptor = 
-                new Disruptor<>(LongEvent::new, bufferSize, DaemonThreadFactory.INSTANCE);
-
-        // 类似于注册处理器
-        disruptor.handleEventsWith(new LongEventHandler());
-        // 或者直接用 lambda
-        disruptor.handleEventsWith((event, sequence, endOfBatch) ->
-                System.out.println("Event: " + event));
-        // 启动我们的 disruptor
-        disruptor.start(); 
-
-
-        RingBuffer<LongEvent> ringBuffer = disruptor.getRingBuffer(); 
-        ByteBuffer bb = ByteBuffer.allocate(8);
-        for (long l = 0; true; l++)
-        {
-            bb.putLong(0, l);
-            // 生产事件
-            ringBuffer.publishEvent((event, sequence, buffer) -> event.set(buffer.getLong(0)), bb);
-            Thread.sleep(1000);
-        }
-    }
-}
-

运行下可以看到运行结果

这里其实就只是最简单的使用,生产者只有一个,然后也不是批量的。

-]]>
- - Java - - - Java - Disruptor - -
Comparator使用小记 /2020/04/05/Comparator%E4%BD%BF%E7%94%A8%E5%B0%8F%E8%AE%B0/ @@ -1806,140 +1648,138 @@ Node *clone(Node *graph) { - Disruptor 系列三 - /2022/09/25/Disruptor-%E7%B3%BB%E5%88%97%E4%B8%89/ - 原来一直有点被误导,
gatingSequences用来标识每个 processer 的操作位点,但是怎么记录更新有点搞不清楚
其实问题在于 gatingSequences 是个 Sequence 数组,首先要看下怎么加进去的,
可以看到是在 com.lmax.disruptor.RingBuffer#addGatingSequences 这个方法里添加
首先是 com.lmax.disruptor.dsl.Disruptor#handleEventsWith(com.lmax.disruptor.EventHandler<? super T>...)
然后执行 com.lmax.disruptor.dsl.Disruptor#createEventProcessors(com.lmax.disruptor.Sequence[], com.lmax.disruptor.EventHandler<? super T>[])

-
EventHandlerGroup<T> createEventProcessors(
-        final Sequence[] barrierSequences,
-        final EventHandler<? super T>[] eventHandlers)
-    {
-        checkNotStarted();
-
-        final Sequence[] processorSequences = new Sequence[eventHandlers.length];
-        final SequenceBarrier barrier = ringBuffer.newBarrier(barrierSequences);
-
-        for (int i = 0, eventHandlersLength = eventHandlers.length; i < eventHandlersLength; i++)
-        {
-            final EventHandler<? super T> eventHandler = eventHandlers[i];
-
-            // 这里将 handler 包装成一个 BatchEventProcessor
-            final BatchEventProcessor<T> batchEventProcessor =
-                new BatchEventProcessor<>(ringBuffer, barrier, eventHandler);
-
-            if (exceptionHandler != null)
-            {
-                batchEventProcessor.setExceptionHandler(exceptionHandler);
-            }
-
-            consumerRepository.add(batchEventProcessor, eventHandler, barrier);
-            processorSequences[i] = batchEventProcessor.getSequence();
-        }
-
-        updateGatingSequencesForNextInChain(barrierSequences, processorSequences);
-
-        return new EventHandlerGroup<>(this, consumerRepository, processorSequences);
-    }
+ Clone Graph Part I + /2014/12/30/Clone-Graph-Part-I/ + problem
Clone a graph. Input is a Node pointer. Return the Node pointer of the cloned graph.
 
-

BatchEventProcessor 在类内有个定义 sequence

-
private final Sequence sequence = new Sequence(Sequencer.INITIAL_CURSOR_VALUE);
-

然后在上面循环中的这一句取出来

-
processorSequences[i] = batchEventProcessor.getSequence();
-

调用com.lmax.disruptor.dsl.Disruptor#updateGatingSequencesForNextInChain 方法

-
private void updateGatingSequencesForNextInChain(final Sequence[] barrierSequences, final Sequence[] processorSequences)
-    {
-        if (processorSequences.length > 0)
-        {
-            // 然后在这里添加
-            ringBuffer.addGatingSequences(processorSequences);
-            for (final Sequence barrierSequence : barrierSequences)
-            {
-                ringBuffer.removeGatingSequence(barrierSequence);
-            }
-            consumerRepository.unMarkEventProcessorsAsEndOfChain(barrierSequences);
-        }
-    }
+A graph is defined below: +struct Node { +vector neighbors; +}
-

而如何更新则是在处理器 com.lmax.disruptor.BatchEventProcessor#run

-
public void run()
+
+

code

typedef unordered_map<Node *, Node *> Map;
+ 
+Node *clone(Node *graph) {
+    if (!graph) return NULL;
+ 
+    Map map;
+    queue<Node *> q;
+    q.push(graph);
+ 
+    Node *graphCopy = new Node();
+    map[graph] = graphCopy;
+ 
+    while (!q.empty()) {
+        Node *node = q.front();
+        q.pop();
+        int n = node->neighbors.size();
+        for (int i = 0; i < n; i++) {
+            Node *neighbor = node->neighbors[i];
+            // no copy exists
+            if (map.find(neighbor) == map.end()) {
+                Node *p = new Node();
+                map[node]->neighbors.push_back(p);
+                map[neighbor] = p;
+                q.push(neighbor);
+            } else {     // a copy already exists
+                map[node]->neighbors.push_back(map[neighbor]);
+            }
+        }
+    }
+ 
+    return graphCopy;
+}
+

anlysis

using the Breadth-first traversal
and use a map to save the neighbors not to be duplicated.

+]]> + + leetcode + + + C++ + leetcode + + + + Disruptor 系列一 + /2022/02/13/Disruptor-%E7%B3%BB%E5%88%97%E4%B8%80/ + 很久之前就听说过这个框架,不过之前有点跟消息队列混起来,这个也是种队列,但不是跟 rocketmq,nsq 那种一样的,而是在进程内部提供队列服务的,偏向于取代ArrayBlockingQueue,因为这个阻塞队列是使用了锁来控制阻塞,关于并发其实有一些通用的最佳实践,就是用锁,即使是 JDK 提供的锁,也是比较耗资源的,当然这是跟不加锁的对比,同样是锁,JDK 的实现还是性能比较优秀的。常见的阻塞队列中例如 ArrayBlockingQueueLinkedBlockingQueue 都有锁的身影的存在,区别在于 ArrayBlockingQueue 是一把锁,后者是两把锁,不过重点不在几把锁,这里其实是两个问题,一个是所谓的 lock free, 对于一个单生产者的 disruptor 来说,因为写入是只有一个线程的,是可以不用加锁,多生产者的时候使用的是 cas 来获取对应的写入坑位,另一个是解决“伪共享”问题,后面可以详细点分析,先介绍下使用
首先是数据源

+
public class LongEvent {
+    private long value;
+
+    public void set(long value) {
+        this.value = value;
+    }
+
+    public long getValue() {
+        return value;
+    }
+
+    public void setValue(long value) {
+        this.value = value;
+    }
+}
+

事件生产

+
public class LongEventFactory implements EventFactory<LongEvent>
+{
+    public LongEvent newInstance()
     {
-        if (running.compareAndSet(IDLE, RUNNING))
-        {
-            sequenceBarrier.clearAlert();
+        return new LongEvent();
+    }
+}
+

事件处理器

+
public class LongEventHandler implements EventHandler<LongEvent> {
 
-            notifyStart();
-            try
-            {
-                if (running.get() == RUNNING)
-                {
-                    processEvents();
-                }
-            }
-            finally
-            {
-                notifyShutdown();
-                running.set(IDLE);
-            }
-        }
-        else
-        {
-            // This is a little bit of guess work.  The running state could of changed to HALTED by
-            // this point.  However, Java does not have compareAndExchange which is the only way
-            // to get it exactly correct.
-            if (running.get() == RUNNING)
-            {
-                throw new IllegalStateException("Thread is already running");
-            }
-            else
-            {
-                earlyExit();
-            }
-        }
-    }
-

然后是

-
private void processEvents()
+    // event 事件,
+    // sequence 当前的序列 
+    // 是否当前批次最后一个数据
+    public void onEvent(LongEvent event, long sequence, boolean endOfBatch)
     {
-        T event = null;
-        long nextSequence = sequence.get() + 1L;
+        String str = String.format("long event : %s l:%s b:%s", event.getValue(), sequence, endOfBatch);
+        System.out.println(str);
+    }
+}
+
+

主方法代码

+
package disruptor;
 
-        while (true)
-        {
-            try
-            {
-                final long availableSequence = sequenceBarrier.waitFor(nextSequence);
-                if (batchStartAware != null)
-                {
-                    batchStartAware.onBatchStart(availableSequence - nextSequence + 1);
-                }
+import com.lmax.disruptor.RingBuffer;
+import com.lmax.disruptor.dsl.Disruptor;
+import com.lmax.disruptor.util.DaemonThreadFactory;
 
-                while (nextSequence <= availableSequence)
-                {
-                    event = dataProvider.get(nextSequence);
-                    eventHandler.onEvent(event, nextSequence, nextSequence == availableSequence);
-                    nextSequence++;
-                }
-                // 如果正常处理完,那就是会更新为 availableSequence,因为都处理好了
-                sequence.set(availableSequence);
-            }
-            catch (final TimeoutException e)
-            {
-                notifyTimeout(sequence.get());
-            }
-            catch (final AlertException ex)
-            {
-                if (running.get() != RUNNING)
-                {
-                    break;
-                }
-            }
-            catch (final Throwable ex)
-            {
-                handleEventException(ex, nextSequence, event);
-                // 如果是异常就只是 nextSequence
-                sequence.set(nextSequence);
-                nextSequence++;
-            }
+import java.nio.ByteBuffer;
+
+public class LongEventMain
+{
+    public static void main(String[] args) throws Exception
+    {
+        // 这个需要是 2 的幂次,这样在定位的时候只需要位移操作,也能减少各种计算操作
+        int bufferSize = 1024; 
+
+        Disruptor<LongEvent> disruptor = 
+                new Disruptor<>(LongEvent::new, bufferSize, DaemonThreadFactory.INSTANCE);
+
+        // 类似于注册处理器
+        disruptor.handleEventsWith(new LongEventHandler());
+        // 或者直接用 lambda
+        disruptor.handleEventsWith((event, sequence, endOfBatch) ->
+                System.out.println("Event: " + event));
+        // 启动我们的 disruptor
+        disruptor.start(); 
+
+
+        RingBuffer<LongEvent> ringBuffer = disruptor.getRingBuffer(); 
+        ByteBuffer bb = ByteBuffer.allocate(8);
+        for (long l = 0; true; l++)
+        {
+            bb.putLong(0, l);
+            // 生产事件
+            ringBuffer.publishEvent((event, sequence, buffer) -> event.set(buffer.getLong(0)), bb);
+            Thread.sleep(1000);
         }
-    }
+ } +}
+

运行下可以看到运行结果

这里其实就只是最简单的使用,生产者只有一个,然后也不是批量的。

]]>
Java @@ -1949,6 +1789,28 @@ Node *clone(Node *graph) { Disruptor
+ + Dubbo 使用的几个记忆点 + /2022/04/02/Dubbo-%E4%BD%BF%E7%94%A8%E7%9A%84%E5%87%A0%E4%B8%AA%E8%AE%B0%E5%BF%86%E7%82%B9/ + 因为后台使用的 dubbo 作为 rpc 框架,并且会有一些日常使用情景有一些小的技巧,在这里做下记录作笔记用

+

dubbo 只拉取不注册

<dubbo:registry address="zookeeper://127.0.0.1:2181" register="false" />
+

就是只要 register="false" 就可以了,这样比如我们在开发环境想运行服务,但又不想让开发环境正常的请求调用到本地来,当然这不是唯一的方式,通过 dubbo 2.7 以上的 tag 路由也可以实现或者自行改造拉取和注册服务的逻辑,因为注册到注册中心的其实是一串带参数的 url,还是比较方便改造的。相反的就是只注册,不拉取

+

dubbo 只注册不拉取

<dubbo:registry address="zookeeper://127.0.0.1:2181" subscribe="false" />
+

这个使用场景就是如果我这个服务只作为 provider,没有任何调用其他的服务,其实就可以这么设置

+

权重配置

<dubbo:provider loadbalance="random" weight="50"/>
+

首先这是在使用了随机的负载均衡策略的时候可以进行配置,并且是对于多个 provider 的情况下,这样其实也可以部分解决上面的只拉取不注册的问题,我把自己的权重调成 0 或者很低

+]]>
+ + Java + Dubbo + + + Java + Dubbo + RPC + 负载均衡 + +
Disruptor 系列二 /2022/02/27/Disruptor-%E7%B3%BB%E5%88%97%E4%BA%8C/ @@ -1988,28 +1850,6 @@ Node *clone(Node *graph) { Disruptor - - Dubbo 使用的几个记忆点 - /2022/04/02/Dubbo-%E4%BD%BF%E7%94%A8%E7%9A%84%E5%87%A0%E4%B8%AA%E8%AE%B0%E5%BF%86%E7%82%B9/ - 因为后台使用的 dubbo 作为 rpc 框架,并且会有一些日常使用情景有一些小的技巧,在这里做下记录作笔记用

-

dubbo 只拉取不注册

<dubbo:registry address="zookeeper://127.0.0.1:2181" register="false" />
-

就是只要 register="false" 就可以了,这样比如我们在开发环境想运行服务,但又不想让开发环境正常的请求调用到本地来,当然这不是唯一的方式,通过 dubbo 2.7 以上的 tag 路由也可以实现或者自行改造拉取和注册服务的逻辑,因为注册到注册中心的其实是一串带参数的 url,还是比较方便改造的。相反的就是只注册,不拉取

-

dubbo 只注册不拉取

<dubbo:registry address="zookeeper://127.0.0.1:2181" subscribe="false" />
-

这个使用场景就是如果我这个服务只作为 provider,没有任何调用其他的服务,其实就可以这么设置

-

权重配置

<dubbo:provider loadbalance="random" weight="50"/>
-

首先这是在使用了随机的负载均衡策略的时候可以进行配置,并且是对于多个 provider 的情况下,这样其实也可以部分解决上面的只拉取不注册的问题,我把自己的权重调成 0 或者很低

-]]>
- - Java - Dubbo - - - Java - Dubbo - RPC - 负载均衡 - -
Filter, Interceptor, Aop, 啥, 啥, 啥? 这些都是啥? /2020/08/22/Filter-Intercepter-Aop-%E5%95%A5-%E5%95%A5-%E5%95%A5-%E8%BF%99%E4%BA%9B%E9%83%BD%E6%98%AF%E5%95%A5/ @@ -2561,608 +2401,250 @@ Node *clone(Node *graph) { - Headscale初体验以及踩坑记 - /2023/01/22/Headscale%E5%88%9D%E4%BD%93%E9%AA%8C%E4%BB%A5%E5%8F%8A%E8%B8%A9%E5%9D%91%E8%AE%B0/ - 最近或者说很久以前就想着能够把几个散装服务器以及家里的网络连起来,譬如一些remote desktop的访问,之前搞了下frp,因为家里电脑没怎么注意安全性就被搞了一下,所以还是想用相对更安全的方式,比如限定ip和端口进行访问,但是感觉ip也不固定就比较难搞,后来看到了 TailscaleHeadscale 的方式,就想着试试看,没想到一开始就踩了几个比较莫名其妙的坑。
可以按官方文档去搭建,也可以在网上找一些其他人搭建的教程。我碰到的主要是关于配置文件的问题

-

第一个问题

Error initializing error="failed to read or create private key: failed to save private key to disk: open /etc/headscale/private.key: read-only file system"
-

其实一开始看到这个我都有点懵了,咋回事呢,read-only file system一般有可能是文件系统出问题了,不可写入,需要重启或者修改挂载方式,被这个错误的错误日志给误导了,后面才知道是配置文件,在另一个教程中也有个类似的回复,一开始没注意,其实就是同一个问题。
默认的配置文件是这样的

-
---
-# headscale will look for a configuration file named `config.yaml` (or `config.json`) in the following order:
-#
-# - `/etc/headscale`
-# - `~/.headscale`
-# - current working directory
-
-# The url clients will connect to.
-# Typically this will be a domain like:
-#
-# https://myheadscale.example.com:443
-#
-server_url: http://127.0.0.1:8080
-
-# Address to listen to / bind to on the server
-#
-# For production:
-# listen_addr: 0.0.0.0:8080
-listen_addr: 127.0.0.1:8080
-
-# Address to listen to /metrics, you may want
-# to keep this endpoint private to your internal
-# network
-#
-metrics_listen_addr: 127.0.0.1:9090
+    JVM源码分析之G1垃圾收集器分析一
+    /2019/12/07/JVM-G1-Part-1/
+    对 Java 的 gc 实现比较感兴趣,原先一般都是看周志明的书,但其实并没有讲具体的 gc 源码,而是把整个思路和流程讲解了一下
特别是 G1 的具体实现
一般对 G1 的理解其实就是把原先整块的新生代老年代分成了以 region 为单位的小块内存,简而言之,就是原先对新生代老年代的收集会涉及到整个代的堆内存空间,而G1 把它变成了更细致的小块内存
这带来了一个很明显的好处和一个很明显的坏处,好处是内存收集可以更灵活,耗时会变短,但整个收集的处理复杂度就变高了
目前看了一点点关于 G1 收集的预期时间相关的代码

+
HeapWord* G1CollectedHeap::do_collection_pause(size_t word_size,
+                                               uint gc_count_before,
+                                               bool* succeeded,
+                                               GCCause::Cause gc_cause) {
+  assert_heap_not_locked_and_not_at_safepoint();
+  VM_G1CollectForAllocation op(word_size,
+                               gc_count_before,
+                               gc_cause,
+                               false, /* should_initiate_conc_mark */
+                               g1_policy()->max_pause_time_ms());
+  VMThread::execute(&op);
 
-# Address to listen for gRPC.
-# gRPC is used for controlling a headscale server
-# remotely with the CLI
-# Note: Remote access _only_ works if you have
-# valid certificates.
-#
-# For production:
-# grpc_listen_addr: 0.0.0.0:50443
-grpc_listen_addr: 127.0.0.1:50443
+  HeapWord* result = op.result();
+  bool ret_succeeded = op.prologue_succeeded() && op.pause_succeeded();
+  assert(result == NULL || ret_succeeded,
+         "the result should be NULL if the VM did not succeed");
+  *succeeded = ret_succeeded;
 
-# Allow the gRPC admin interface to run in INSECURE
-# mode. This is not recommended as the traffic will
-# be unencrypted. Only enable if you know what you
-# are doing.
-grpc_allow_insecure: false
+  assert_heap_not_locked();
+  return result;
+}
+

这里就是收集时需要停顿的,其中VMThread::execute(&op);是具体执行的,真正执行的是VM_G1CollectForAllocation::doit方法

+
void VM_G1CollectForAllocation::doit() {
+  G1CollectedHeap* g1h = G1CollectedHeap::heap();
+  assert(!_should_initiate_conc_mark || g1h->should_do_concurrent_full_gc(_gc_cause),
+      "only a GC locker, a System.gc(), stats update, whitebox, or a hum allocation induced GC should start a cycle");
 
-# Private key used to encrypt the traffic between headscale
-# and Tailscale clients.
-# The private key file will be autogenerated if it's missing.
-#
-# For production:
-# /var/lib/headscale/private.key
-private_key_path: ./private.key
+  if (_word_size > 0) {
+    // An allocation has been requested. So, try to do that first.
+    _result = g1h->attempt_allocation_at_safepoint(_word_size,
+                                                   false /* expect_null_cur_alloc_region */);
+    if (_result != NULL) {
+      // If we can successfully allocate before we actually do the
+      // pause then we will consider this pause successful.
+      _pause_succeeded = true;
+      return;
+    }
+  }
 
-# The Noise section includes specific configuration for the
-# TS2021 Noise protocol
-noise:
-  # The Noise private key is used to encrypt the
-  # traffic between headscale and Tailscale clients when
-  # using the new Noise-based protocol. It must be different
-  # from the legacy private key.
-  #
-  # For production:
-  # private_key_path: /var/lib/headscale/noise_private.key
-  private_key_path: ./noise_private.key
+  GCCauseSetter x(g1h, _gc_cause);
+  if (_should_initiate_conc_mark) {
+    // It's safer to read old_marking_cycles_completed() here, given
+    // that noone else will be updating it concurrently. Since we'll
+    // only need it if we're initiating a marking cycle, no point in
+    // setting it earlier.
+    _old_marking_cycles_completed_before = g1h->old_marking_cycles_completed();
 
-# List of IP prefixes to allocate tailaddresses from.
-# Each prefix consists of either an IPv4 or IPv6 address,
-# and the associated prefix length, delimited by a slash.
-# While this looks like it can take arbitrary values, it
-# needs to be within IP ranges supported by the Tailscale
-# client.
-# IPv6: https://github.com/tailscale/tailscale/blob/22ebb25e833264f58d7c3f534a8b166894a89536/net/tsaddr/tsaddr.go#LL81C52-L81C71
-# IPv4: https://github.com/tailscale/tailscale/blob/22ebb25e833264f58d7c3f534a8b166894a89536/net/tsaddr/tsaddr.go#L33
-ip_prefixes:
-  - fd7a:115c:a1e0::/48
-  - 100.64.0.0/10
+    // At this point we are supposed to start a concurrent cycle. We
+    // will do so if one is not already in progress.
+    bool res = g1h->g1_policy()->force_initial_mark_if_outside_cycle(_gc_cause);
 
-# DERP is a relay system that Tailscale uses when a direct
-# connection cannot be established.
-# https://tailscale.com/blog/how-tailscale-works/#encrypted-tcp-relays-derp
-#
-# headscale needs a list of DERP servers that can be presented
-# to the clients.
-derp:
-  server:
-    # If enabled, runs the embedded DERP server and merges it into the rest of the DERP config
-    # The Headscale server_url defined above MUST be using https, DERP requires TLS to be in place
-    enabled: false
+    // The above routine returns true if we were able to force the
+    // next GC pause to be an initial mark; it returns false if a
+    // marking cycle is already in progress.
+    //
+    // If a marking cycle is already in progress just return and skip the
+    // pause below - if the reason for requesting this initial mark pause
+    // was due to a System.gc() then the requesting thread should block in
+    // doit_epilogue() until the marking cycle is complete.
+    //
+    // If this initial mark pause was requested as part of a humongous
+    // allocation then we know that the marking cycle must just have
+    // been started by another thread (possibly also allocating a humongous
+    // object) as there was no active marking cycle when the requesting
+    // thread checked before calling collect() in
+    // attempt_allocation_humongous(). Retrying the GC, in this case,
+    // will cause the requesting thread to spin inside collect() until the
+    // just started marking cycle is complete - which may be a while. So
+    // we do NOT retry the GC.
+    if (!res) {
+      assert(_word_size == 0, "Concurrent Full GC/Humongous Object IM shouldn't be allocating");
+      if (_gc_cause != GCCause::_g1_humongous_allocation) {
+        _should_retry_gc = true;
+      }
+      return;
+    }
+  }
 
-    # Region ID to use for the embedded DERP server.
-    # The local DERP prevails if the region ID collides with other region ID coming from
-    # the regular DERP config.
-    region_id: 999
+  // Try a partial collection of some kind.
+  _pause_succeeded = g1h->do_collection_pause_at_safepoint(_target_pause_time_ms);
 
-    # Region code and name are displayed in the Tailscale UI to identify a DERP region
-    region_code: "headscale"
-    region_name: "Headscale Embedded DERP"
+  if (_pause_succeeded) {
+    if (_word_size > 0) {
+      // An allocation had been requested. Do it, eventually trying a stronger
+      // kind of GC.
+      _result = g1h->satisfy_failed_allocation(_word_size, &_pause_succeeded);
+    } else {
+      bool should_upgrade_to_full = !g1h->should_do_concurrent_full_gc(_gc_cause) &&
+                                    !g1h->has_regions_left_for_allocation();
+      if (should_upgrade_to_full) {
+        // There has been a request to perform a GC to free some space. We have no
+        // information on how much memory has been asked for. In case there are
+        // absolutely no regions left to allocate into, do a maximally compacting full GC.
+        log_info(gc, ergo)("Attempting maximally compacting collection");
+        _pause_succeeded = g1h->do_full_collection(false, /* explicit gc */
+                                                   true   /* clear_all_soft_refs */);
+      }
+    }
+    guarantee(_pause_succeeded, "Elevated collections during the safepoint must always succeed.");
+  } else {
+    assert(_result == NULL, "invariant");
+    // The only reason for the pause to not be successful is that, the GC locker is
+    // active (or has become active since the prologue was executed). In this case
+    // we should retry the pause after waiting for the GC locker to become inactive.
+    _should_retry_gc = true;
+  }
+}
+

这里可以看到核心的是G1CollectedHeap::do_collection_pause_at_safepoint这个方法,它带上了目标暂停时间的值

+
G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
+  assert_at_safepoint_on_vm_thread();
+  guarantee(!is_gc_active(), "collection is not reentrant");
 
-    # Listens over UDP at the configured address for STUN connections - to help with NAT traversal.
-    # When the embedded DERP server is enabled stun_listen_addr MUST be defined.
-    #
-    # For more details on how this works, check this great article: https://tailscale.com/blog/how-tailscale-works/
-    stun_listen_addr: "0.0.0.0:3478"
+  if (GCLocker::check_active_before_gc()) {
+    return false;
+  }
 
-  # List of externally available DERP maps encoded in JSON
-  urls:
-    - https://controlplane.tailscale.com/derpmap/default
+  _gc_timer_stw->register_gc_start();
 
-  # Locally available DERP map files encoded in YAML
-  #
-  # This option is mostly interesting for people hosting
-  # their own DERP servers:
-  # https://tailscale.com/kb/1118/custom-derp-servers/
-  #
-  # paths:
-  #   - /etc/headscale/derp-example.yaml
-  paths: []
+  GCIdMark gc_id_mark;
+  _gc_tracer_stw->report_gc_start(gc_cause(), _gc_timer_stw->gc_start());
 
-  # If enabled, a worker will be set up to periodically
-  # refresh the given sources and update the derpmap
-  # will be set up.
-  auto_update_enabled: true
+  SvcGCMarker sgcm(SvcGCMarker::MINOR);
+  ResourceMark rm;
 
-  # How often should we check for DERP updates?
-  update_frequency: 24h
+  g1_policy()->note_gc_start();
 
-# Disables the automatic check for headscale updates on startup
-disable_check_updates: false
+  wait_for_root_region_scanning();
 
-# Time before an inactive ephemeral node is deleted?
-ephemeral_node_inactivity_timeout: 30m
+  print_heap_before_gc();
+  print_heap_regions();
+  trace_heap_before_gc(_gc_tracer_stw);
 
-# Period to check for node updates within the tailnet. A value too low will severely affect
-# CPU consumption of Headscale. A value too high (over 60s) will cause problems
-# for the nodes, as they won't get updates or keep alive messages frequently enough.
-# In case of doubts, do not touch the default 10s.
-node_update_check_interval: 10s
+  _verifier->verify_region_sets_optional();
+  _verifier->verify_dirty_young_regions();
 
-# SQLite config
-db_type: sqlite3
+  // We should not be doing initial mark unless the conc mark thread is running
+  if (!_cm_thread->should_terminate()) {
+    // This call will decide whether this pause is an initial-mark
+    // pause. If it is, in_initial_mark_gc() will return true
+    // for the duration of this pause.
+    g1_policy()->decide_on_conc_mark_initiation();
+  }
 
-# For production:
-# db_path: /var/lib/headscale/db.sqlite
-db_path: ./db.sqlite
+  // We do not allow initial-mark to be piggy-backed on a mixed GC.
+  assert(!collector_state()->in_initial_mark_gc() ||
+          collector_state()->in_young_only_phase(), "sanity");
 
-# # Postgres config
-# If using a Unix socket to connect to Postgres, set the socket path in the 'host' field and leave 'port' blank.
-# db_type: postgres
-# db_host: localhost
-# db_port: 5432
-# db_name: headscale
-# db_user: foo
-# db_pass: bar
+  // We also do not allow mixed GCs during marking.
+  assert(!collector_state()->mark_or_rebuild_in_progress() || collector_state()->in_young_only_phase(), "sanity");
 
-# If other 'sslmode' is required instead of 'require(true)' and 'disabled(false)', set the 'sslmode' you need
-# in the 'db_ssl' field. Refers to https://www.postgresql.org/docs/current/libpq-ssl.html Table 34.1.
-# db_ssl: false
+  // Record whether this pause is an initial mark. When the current
+  // thread has completed its logging output and it's safe to signal
+  // the CM thread, the flag's value in the policy has been reset.
+  bool should_start_conc_mark = collector_state()->in_initial_mark_gc();
 
-### TLS configuration
-#
-## Let's encrypt / ACME
-#
-# headscale supports automatically requesting and setting up
-# TLS for a domain with Let's Encrypt.
-#
-# URL to ACME directory
-acme_url: https://acme-v02.api.letsencrypt.org/directory
+  // Inner scope for scope based logging, timers, and stats collection
+  {
+    EvacuationInfo evacuation_info;
 
-# Email to register with ACME provider
-acme_email: ""
+    if (collector_state()->in_initial_mark_gc()) {
+      // We are about to start a marking cycle, so we increment the
+      // full collection counter.
+      increment_old_marking_cycles_started();
+      _cm->gc_tracer_cm()->set_gc_cause(gc_cause());
+    }
 
-# Domain name to request a TLS certificate for:
-tls_letsencrypt_hostname: ""
+    _gc_tracer_stw->report_yc_type(collector_state()->yc_type());
 
-# Path to store certificates and metadata needed by
-# letsencrypt
-# For production:
-# tls_letsencrypt_cache_dir: /var/lib/headscale/cache
-tls_letsencrypt_cache_dir: ./cache
+    GCTraceCPUTime tcpu;
 
-# Type of ACME challenge to use, currently supported types:
-# HTTP-01 or TLS-ALPN-01
-# See [docs/tls.md](docs/tls.md) for more information
-tls_letsencrypt_challenge_type: HTTP-01
-# When HTTP-01 challenge is chosen, letsencrypt must set up a
-# verification endpoint, and it will be listening on:
-# :http = port 80
-tls_letsencrypt_listen: ":http"
+    G1HeapVerifier::G1VerifyType verify_type;
+    FormatBuffer<> gc_string("Pause Young ");
+    if (collector_state()->in_initial_mark_gc()) {
+      gc_string.append("(Concurrent Start)");
+      verify_type = G1HeapVerifier::G1VerifyConcurrentStart;
+    } else if (collector_state()->in_young_only_phase()) {
+      if (collector_state()->in_young_gc_before_mixed()) {
+        gc_string.append("(Prepare Mixed)");
+      } else {
+        gc_string.append("(Normal)");
+      }
+      verify_type = G1HeapVerifier::G1VerifyYoungNormal;
+    } else {
+      gc_string.append("(Mixed)");
+      verify_type = G1HeapVerifier::G1VerifyMixed;
+    }
+    GCTraceTime(Info, gc) tm(gc_string, NULL, gc_cause(), true);
 
-## Use already defined certificates:
-tls_cert_path: ""
-tls_key_path: ""
+    uint active_workers = AdaptiveSizePolicy::calc_active_workers(workers()->total_workers(),
+                                                                  workers()->active_workers(),
+                                                                  Threads::number_of_non_daemon_threads());
+    active_workers = workers()->update_active_workers(active_workers);
+    log_info(gc,task)("Using %u workers of %u for evacuation", active_workers, workers()->total_workers());
 
-log:
-  # Output formatting for logs: text or json
-  format: text
-  level: info
+    TraceCollectorStats tcs(g1mm()->incremental_collection_counters());
+    TraceMemoryManagerStats tms(&_memory_manager, gc_cause(),
+                                collector_state()->yc_type() == Mixed /* allMemoryPoolsAffected */);
 
-# Path to a file containg ACL policies.
-# ACLs can be defined as YAML or HUJSON.
-# https://tailscale.com/kb/1018/acls/
-acl_policy_path: ""
+    G1HeapTransition heap_transition(this);
+    size_t heap_used_bytes_before_gc = used();
 
-## DNS
-#
-# headscale supports Tailscale's DNS configuration and MagicDNS.
-# Please have a look to their KB to better understand the concepts:
-#
-# - https://tailscale.com/kb/1054/dns/
-# - https://tailscale.com/kb/1081/magicdns/
-# - https://tailscale.com/blog/2021-09-private-dns-with-magicdns/
-#
-dns_config:
-  # Whether to prefer using Headscale provided DNS or use local.
-  override_local_dns: true
+    // Don't dynamically change the number of GC threads this early.  A value of
+    // 0 is used to indicate serial work.  When parallel work is done,
+    // it will be set.
 
-  # List of DNS servers to expose to clients.
-  nameservers:
-    - 1.1.1.1
+    { // Call to jvmpi::post_class_unload_events must occur outside of active GC
+      IsGCActiveMark x;
 
-  # NextDNS (see https://tailscale.com/kb/1218/nextdns/).
-  # "abc123" is example NextDNS ID, replace with yours.
-  #
-  # With metadata sharing:
-  # nameservers:
-  #   - https://dns.nextdns.io/abc123
-  #
-  # Without metadata sharing:
-  # nameservers:
-  #   - 2a07:a8c0::ab:c123
-  #   - 2a07:a8c1::ab:c123
+      gc_prologue(false);
 
-  # Split DNS (see https://tailscale.com/kb/1054/dns/),
-  # list of search domains and the DNS to query for each one.
-  #
-  # restricted_nameservers:
-  #   foo.bar.com:
-  #     - 1.1.1.1
-  #   darp.headscale.net:
-  #     - 1.1.1.1
-  #     - 8.8.8.8
+      if (VerifyRememberedSets) {
+        log_info(gc, verify)("[Verifying RemSets before GC]");
+        VerifyRegionRemSetClosure v_cl;
+        heap_region_iterate(&v_cl);
+      }
 
-  # Search domains to inject.
-  domains: []
+      _verifier->verify_before_gc(verify_type);
 
-  # Extra DNS records
-  # so far only A-records are supported (on the tailscale side)
-  # See https://github.com/juanfont/headscale/blob/main/docs/dns-records.md#Limitations
-  # extra_records:
-  #   - name: "grafana.myvpn.example.com"
-  #     type: "A"
-  #     value: "100.64.0.3"
-  #
-  #   # you can also put it in one line
-  #   - { name: "prometheus.myvpn.example.com", type: "A", value: "100.64.0.3" }
+      _verifier->check_bitmaps("GC Start");
 
-  # Whether to use [MagicDNS](https://tailscale.com/kb/1081/magicdns/).
-  # Only works if there is at least a nameserver defined.
-  magic_dns: true
+#if COMPILER2_OR_JVMCI
+      DerivedPointerTable::clear();
+#endif
 
-  # Defines the base domain to create the hostnames for MagicDNS.
-  # `base_domain` must be a FQDNs, without the trailing dot.
-  # The FQDN of the hosts will be
-  # `hostname.user.base_domain` (e.g., _myhost.myuser.example.com_).
-  base_domain: example.com
+      // Please see comment in g1CollectedHeap.hpp and
+      // G1CollectedHeap::ref_processing_init() to see how
+      // reference processing currently works in G1.
 
-# Unix socket used for the CLI to connect without authentication
-# Note: for production you will want to set this to something like:
-# unix_socket: /var/run/headscale.sock
-unix_socket: ./headscale.sock
-unix_socket_permission: "0770"
-#
-# headscale supports experimental OpenID connect support,
-# it is still being tested and might have some bugs, please
-# help us test it.
-# OpenID Connect
-# oidc:
-#   only_start_if_oidc_is_available: true
-#   issuer: "https://your-oidc.issuer.com/path"
-#   client_id: "your-oidc-client-id"
-#   client_secret: "your-oidc-client-secret"
-#   # Alternatively, set `client_secret_path` to read the secret from the file.
-#   # It resolves environment variables, making integration to systemd's
-#   # `LoadCredential` straightforward:
-#   client_secret_path: "${CREDENTIALS_DIRECTORY}/oidc_client_secret"
-#   # client_secret and client_secret_path are mutually exclusive.
-#
-#   Customize the scopes used in the OIDC flow, defaults to "openid", "profile" and "email" and add custom query
-#   parameters to the Authorize Endpoint request. Scopes default to "openid", "profile" and "email".
-#
-#   scope: ["openid", "profile", "email", "custom"]
-#   extra_params:
-#     domain_hint: example.com
-#
-#   List allowed principal domains and/or users. If an authenticated user's domain is not in this list, the
-#   authentication request will be rejected.
-#
-#   allowed_domains:
-#     - example.com
-# Groups from keycloak have a leading '/'
-#   allowed_groups:
-#     - /headscale
-#   allowed_users:
-#     - alice@example.com
-#
-#   If `strip_email_domain` is set to `true`, the domain part of the username email address will be removed.
-#   This will transform `first-name.last-name@example.com` to the user `first-name.last-name`
-#   If `strip_email_domain` is set to `false` the domain part will NOT be removed resulting to the following
-#   user: `first-name.last-name.example.com`
-#
-#   strip_email_domain: true
+      // Enable discovery in the STW reference processor
+      _ref_processor_stw->enable_discovery();
 
-# Logtail configuration
-# Logtail is Tailscales logging and auditing infrastructure, it allows the control panel
-# to instruct tailscale nodes to log their activity to a remote server.
-logtail:
-  # Enable logtail for this headscales clients.
-  # As there is currently no support for overriding the log server in headscale, this is
-  # disabled by default. Enabling this will make your clients send logs to Tailscale Inc.
-  enabled: false
+      {
+        // We want to temporarily turn off discovery by the
+        // CM ref processor, if necessary, and turn it back on
+        // on again later if we do. Using a scoped
+        // NoRefDiscovery object will do this.
+        NoRefDiscovery no_cm_discovery(_ref_processor_cm);
 
-# Enabling this option makes devices prefer a random port for WireGuard traffic over the
-# default static port 41641. This option is intended as a workaround for some buggy
-# firewall devices. See https://tailscale.com/kb/1181/firewalls/ for more information.
-randomize_client_port: false
- -

问题就是出在几个文件路径的配置,默认都是当前目录,也就是headscale的可执行文件所在目录,需要按它配置说明中的生产配置进行修改

-
# For production:
-# /var/lib/headscale/private.key
-private_key_path: /var/lib/headscale/private.key
-

直接改成绝对路径就好了,还有两个文件路径
另一个也是个秘钥的路径问题

-
noise:
-  # The Noise private key is used to encrypt the
-  # traffic between headscale and Tailscale clients when
-  # using the new Noise-based protocol. It must be different
-  # from the legacy private key.
-  #
-  # For production:
-  # private_key_path: /var/lib/headscale/noise_private.key
-  private_key_path: /var/lib/headscale/noise_private.key
-

第二个问题

这个问题也是一种误导,
错误信息是

-
Error initializing error="unable to open database file: out of memory (14)"
-

这就是个文件,内存也完全没有被占满的迹象,原来也是文件路径的问题

-
# For production:
-# db_path: /var/lib/headscale/db.sqlite
-db_path: /var/lib/headscale/db.sqlite
-

都改成绝对路径就可以了,然后这里还有个就是要对/var/lib/headscale//etc/headscale/等路径赋予headscale用户权限,有时候对这类问题的排查真的蛮头疼,日志报错都不是真实的错误信息,开源项目对这些错误的提示真的也需要优化,后续的譬如mac也加入节点等后面再开篇讲

-]]>
- - headscale - - - headscale - - - - JVM源码分析之G1垃圾收集器分析一 - /2019/12/07/JVM-G1-Part-1/ - 对 Java 的 gc 实现比较感兴趣,原先一般都是看周志明的书,但其实并没有讲具体的 gc 源码,而是把整个思路和流程讲解了一下
特别是 G1 的具体实现
一般对 G1 的理解其实就是把原先整块的新生代老年代分成了以 region 为单位的小块内存,简而言之,就是原先对新生代老年代的收集会涉及到整个代的堆内存空间,而G1 把它变成了更细致的小块内存
这带来了一个很明显的好处和一个很明显的坏处,好处是内存收集可以更灵活,耗时会变短,但整个收集的处理复杂度就变高了
目前看了一点点关于 G1 收集的预期时间相关的代码

-
HeapWord* G1CollectedHeap::do_collection_pause(size_t word_size,
-                                               uint gc_count_before,
-                                               bool* succeeded,
-                                               GCCause::Cause gc_cause) {
-  assert_heap_not_locked_and_not_at_safepoint();
-  VM_G1CollectForAllocation op(word_size,
-                               gc_count_before,
-                               gc_cause,
-                               false, /* should_initiate_conc_mark */
-                               g1_policy()->max_pause_time_ms());
-  VMThread::execute(&op);
-
-  HeapWord* result = op.result();
-  bool ret_succeeded = op.prologue_succeeded() && op.pause_succeeded();
-  assert(result == NULL || ret_succeeded,
-         "the result should be NULL if the VM did not succeed");
-  *succeeded = ret_succeeded;
-
-  assert_heap_not_locked();
-  return result;
-}
-

这里就是收集时需要停顿的,其中VMThread::execute(&op);是具体执行的,真正执行的是VM_G1CollectForAllocation::doit方法

-
void VM_G1CollectForAllocation::doit() {
-  G1CollectedHeap* g1h = G1CollectedHeap::heap();
-  assert(!_should_initiate_conc_mark || g1h->should_do_concurrent_full_gc(_gc_cause),
-      "only a GC locker, a System.gc(), stats update, whitebox, or a hum allocation induced GC should start a cycle");
-
-  if (_word_size > 0) {
-    // An allocation has been requested. So, try to do that first.
-    _result = g1h->attempt_allocation_at_safepoint(_word_size,
-                                                   false /* expect_null_cur_alloc_region */);
-    if (_result != NULL) {
-      // If we can successfully allocate before we actually do the
-      // pause then we will consider this pause successful.
-      _pause_succeeded = true;
-      return;
-    }
-  }
-
-  GCCauseSetter x(g1h, _gc_cause);
-  if (_should_initiate_conc_mark) {
-    // It's safer to read old_marking_cycles_completed() here, given
-    // that noone else will be updating it concurrently. Since we'll
-    // only need it if we're initiating a marking cycle, no point in
-    // setting it earlier.
-    _old_marking_cycles_completed_before = g1h->old_marking_cycles_completed();
-
-    // At this point we are supposed to start a concurrent cycle. We
-    // will do so if one is not already in progress.
-    bool res = g1h->g1_policy()->force_initial_mark_if_outside_cycle(_gc_cause);
-
-    // The above routine returns true if we were able to force the
-    // next GC pause to be an initial mark; it returns false if a
-    // marking cycle is already in progress.
-    //
-    // If a marking cycle is already in progress just return and skip the
-    // pause below - if the reason for requesting this initial mark pause
-    // was due to a System.gc() then the requesting thread should block in
-    // doit_epilogue() until the marking cycle is complete.
-    //
-    // If this initial mark pause was requested as part of a humongous
-    // allocation then we know that the marking cycle must just have
-    // been started by another thread (possibly also allocating a humongous
-    // object) as there was no active marking cycle when the requesting
-    // thread checked before calling collect() in
-    // attempt_allocation_humongous(). Retrying the GC, in this case,
-    // will cause the requesting thread to spin inside collect() until the
-    // just started marking cycle is complete - which may be a while. So
-    // we do NOT retry the GC.
-    if (!res) {
-      assert(_word_size == 0, "Concurrent Full GC/Humongous Object IM shouldn't be allocating");
-      if (_gc_cause != GCCause::_g1_humongous_allocation) {
-        _should_retry_gc = true;
-      }
-      return;
-    }
-  }
-
-  // Try a partial collection of some kind.
-  _pause_succeeded = g1h->do_collection_pause_at_safepoint(_target_pause_time_ms);
-
-  if (_pause_succeeded) {
-    if (_word_size > 0) {
-      // An allocation had been requested. Do it, eventually trying a stronger
-      // kind of GC.
-      _result = g1h->satisfy_failed_allocation(_word_size, &_pause_succeeded);
-    } else {
-      bool should_upgrade_to_full = !g1h->should_do_concurrent_full_gc(_gc_cause) &&
-                                    !g1h->has_regions_left_for_allocation();
-      if (should_upgrade_to_full) {
-        // There has been a request to perform a GC to free some space. We have no
-        // information on how much memory has been asked for. In case there are
-        // absolutely no regions left to allocate into, do a maximally compacting full GC.
-        log_info(gc, ergo)("Attempting maximally compacting collection");
-        _pause_succeeded = g1h->do_full_collection(false, /* explicit gc */
-                                                   true   /* clear_all_soft_refs */);
-      }
-    }
-    guarantee(_pause_succeeded, "Elevated collections during the safepoint must always succeed.");
-  } else {
-    assert(_result == NULL, "invariant");
-    // The only reason for the pause to not be successful is that, the GC locker is
-    // active (or has become active since the prologue was executed). In this case
-    // we should retry the pause after waiting for the GC locker to become inactive.
-    _should_retry_gc = true;
-  }
-}
-

这里可以看到核心的是G1CollectedHeap::do_collection_pause_at_safepoint这个方法,它带上了目标暂停时间的值

-
G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
-  assert_at_safepoint_on_vm_thread();
-  guarantee(!is_gc_active(), "collection is not reentrant");
-
-  if (GCLocker::check_active_before_gc()) {
-    return false;
-  }
-
-  _gc_timer_stw->register_gc_start();
-
-  GCIdMark gc_id_mark;
-  _gc_tracer_stw->report_gc_start(gc_cause(), _gc_timer_stw->gc_start());
-
-  SvcGCMarker sgcm(SvcGCMarker::MINOR);
-  ResourceMark rm;
-
-  g1_policy()->note_gc_start();
-
-  wait_for_root_region_scanning();
-
-  print_heap_before_gc();
-  print_heap_regions();
-  trace_heap_before_gc(_gc_tracer_stw);
-
-  _verifier->verify_region_sets_optional();
-  _verifier->verify_dirty_young_regions();
-
-  // We should not be doing initial mark unless the conc mark thread is running
-  if (!_cm_thread->should_terminate()) {
-    // This call will decide whether this pause is an initial-mark
-    // pause. If it is, in_initial_mark_gc() will return true
-    // for the duration of this pause.
-    g1_policy()->decide_on_conc_mark_initiation();
-  }
-
-  // We do not allow initial-mark to be piggy-backed on a mixed GC.
-  assert(!collector_state()->in_initial_mark_gc() ||
-          collector_state()->in_young_only_phase(), "sanity");
-
-  // We also do not allow mixed GCs during marking.
-  assert(!collector_state()->mark_or_rebuild_in_progress() || collector_state()->in_young_only_phase(), "sanity");
-
-  // Record whether this pause is an initial mark. When the current
-  // thread has completed its logging output and it's safe to signal
-  // the CM thread, the flag's value in the policy has been reset.
-  bool should_start_conc_mark = collector_state()->in_initial_mark_gc();
-
-  // Inner scope for scope based logging, timers, and stats collection
-  {
-    EvacuationInfo evacuation_info;
-
-    if (collector_state()->in_initial_mark_gc()) {
-      // We are about to start a marking cycle, so we increment the
-      // full collection counter.
-      increment_old_marking_cycles_started();
-      _cm->gc_tracer_cm()->set_gc_cause(gc_cause());
-    }
-
-    _gc_tracer_stw->report_yc_type(collector_state()->yc_type());
-
-    GCTraceCPUTime tcpu;
-
-    G1HeapVerifier::G1VerifyType verify_type;
-    FormatBuffer<> gc_string("Pause Young ");
-    if (collector_state()->in_initial_mark_gc()) {
-      gc_string.append("(Concurrent Start)");
-      verify_type = G1HeapVerifier::G1VerifyConcurrentStart;
-    } else if (collector_state()->in_young_only_phase()) {
-      if (collector_state()->in_young_gc_before_mixed()) {
-        gc_string.append("(Prepare Mixed)");
-      } else {
-        gc_string.append("(Normal)");
-      }
-      verify_type = G1HeapVerifier::G1VerifyYoungNormal;
-    } else {
-      gc_string.append("(Mixed)");
-      verify_type = G1HeapVerifier::G1VerifyMixed;
-    }
-    GCTraceTime(Info, gc) tm(gc_string, NULL, gc_cause(), true);
-
-    uint active_workers = AdaptiveSizePolicy::calc_active_workers(workers()->total_workers(),
-                                                                  workers()->active_workers(),
-                                                                  Threads::number_of_non_daemon_threads());
-    active_workers = workers()->update_active_workers(active_workers);
-    log_info(gc,task)("Using %u workers of %u for evacuation", active_workers, workers()->total_workers());
-
-    TraceCollectorStats tcs(g1mm()->incremental_collection_counters());
-    TraceMemoryManagerStats tms(&_memory_manager, gc_cause(),
-                                collector_state()->yc_type() == Mixed /* allMemoryPoolsAffected */);
-
-    G1HeapTransition heap_transition(this);
-    size_t heap_used_bytes_before_gc = used();
-
-    // Don't dynamically change the number of GC threads this early.  A value of
-    // 0 is used to indicate serial work.  When parallel work is done,
-    // it will be set.
-
-    { // Call to jvmpi::post_class_unload_events must occur outside of active GC
-      IsGCActiveMark x;
-
-      gc_prologue(false);
-
-      if (VerifyRememberedSets) {
-        log_info(gc, verify)("[Verifying RemSets before GC]");
-        VerifyRegionRemSetClosure v_cl;
-        heap_region_iterate(&v_cl);
-      }
-
-      _verifier->verify_before_gc(verify_type);
-
-      _verifier->check_bitmaps("GC Start");
-
-#if COMPILER2_OR_JVMCI
-      DerivedPointerTable::clear();
-#endif
-
-      // Please see comment in g1CollectedHeap.hpp and
-      // G1CollectedHeap::ref_processing_init() to see how
-      // reference processing currently works in G1.
-
-      // Enable discovery in the STW reference processor
-      _ref_processor_stw->enable_discovery();
-
-      {
-        // We want to temporarily turn off discovery by the
-        // CM ref processor, if necessary, and turn it back on
-        // on again later if we do. Using a scoped
-        // NoRefDiscovery object will do this.
-        NoRefDiscovery no_cm_discovery(_ref_processor_cm);
-
-        // Forget the current alloc region (we might even choose it to be part
-        // of the collection set!).
-        _allocator->release_mutator_alloc_region();
+        // Forget the current alloc region (we might even choose it to be part
+        // of the collection set!).
+        _allocator->release_mutator_alloc_region();
 
         // This timing is only used by the ergonomics to handle our pause target.
         // It is unclear why this should not include the full pause. We will
@@ -3525,26 +3007,117 @@ Node *clone(Node *graph) {
       
   
   
-    Leetcode 021 合并两个有序链表 ( Merge Two Sorted Lists ) 题解分析
-    /2021/10/07/Leetcode-021-%E5%90%88%E5%B9%B6%E4%B8%A4%E4%B8%AA%E6%9C%89%E5%BA%8F%E9%93%BE%E8%A1%A8-Merge-Two-Sorted-Lists-%E9%A2%98%E8%A7%A3%E5%88%86%E6%9E%90/
-    题目介绍

Merge two sorted linked lists and return it as a sorted list. The list should be made by splicing together the nodes of the first two lists.

-

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

-

示例 1

-
-

输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]

-
-

示例 2

-

输入: l1 = [], l2 = []
输出: []

-
-

示例 3

-

输入: l1 = [], l2 = [0]
输出: [0]

-
-

简要分析

这题是 Easy 的,看着也挺简单,两个链表进行合并,就是比较下大小,可能将就点的话最好就在两个链表中原地合并

-

题解代码

public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
-        // 下面两个if判断了入参的边界,如果其一为null,直接返回另一个就可以了
-        if (l1 == null) {
-            return l2;
-        }
+    2022 年终总结
+    /2023/01/15/2022-%E5%B9%B4%E7%BB%88%E6%80%BB%E7%BB%93/
+    一年又一年,时间匆匆,这一年过得不太容易,很多事情都是来得猝不及防,很多规划也照例是没有完成,今年更多了一些,又是比较丧的一篇总结
工作上的变化让我多理解了一些社会跟职场的现实吧,可能的确是我不够优秀,也可能是其他,说回我自身,在工作中今年应该是收获比较一般的一年,不能说没有,对原先不熟悉的业务的掌握程度有了比较大的提升,只是问题依旧存在,也挺难推动完全改变,只能尽自己所能,而这一点也主要是在团队中的定位因为前面说的一些原因,在前期不明确,限制比较大,虽然现在并没有完全解决,但也有了一些明显的改善,如果明年继续为这家公司服务,希望能有所突破,在人心沟通上的技巧总是比较反感,可也是不得不使用或者说被迫学习使用的,LD说我的对错观太强了,拗不过来,希望能有所改变。
长远的规划上没有什么明确的想法,很容易否定原来的各种想法,见识过各种现实的残酷,明白以前的一些想法不够全面或者比较幼稚,想有更上一层楼的机会,只是不希望是通过自己不认可的方式。比较能接受的是通过提升自己的技术和执行力,能够有更进一步的可能。
技术上是挺失败的去年跟前年还是能看一些书,学一些东西,今年少了很多,可能对原来比较熟悉的都有些遗忘,最近有在改善博客的内容,能更多的是系列化的,由浅入深,只是还很不完善,没什么规划,体系上也还不完整,不过还是以mybatis作为一个开头,后续新开始的内容或者原先写过的相关的都能做个整理,不再是想到啥就写点啥。最近的一个重点是在k8s上,学习方式跟一些特别优秀的人比起来还是会慢一些,不过也是自己的方法,能够更深入的理解整个体系,并讲解出来,可能会尝试采用视频的方式,对一些比较好的内容做尝试,看看会不会有比较好的数据和反馈,在22年还苟着周更的独立技术博客也算是比较稀有了的,其他站的发布也要勤一些,形成所谓的“矩阵”。
跑步减肥这个么还是比较惨,22年只跑了368公里,比21年少了85公里,有一些客观但很多是主观的原因,还是需要跑起来,只是减肥也很迫切,体重比较大跑步还是有些压力的,买了动感单车,就是时间稍长屁股痛这个目前比较难解决,骑还是每天在骑就是强度跟时间不太够,要保证每天30分钟的量可能会比较好。
加油吧,愿23年家人和自己都健康,顺遂。大家也一样。

+]]>
+ + 生活 + 年终总结 + + + 生活 + 年终总结 + 2022 + 2023 + + + + Leetcode 028 实现 strStr() ( Implement strStr() ) 题解分析 + /2021/10/31/Leetcode-028-%E5%AE%9E%E7%8E%B0-strStr-Implement-strStr-%E9%A2%98%E8%A7%A3%E5%88%86%E6%9E%90/ + 题目介绍

Implement strStr().

+

Return the index of the first occurrence of needle in haystack, or -1 if needle is not part of haystack.

+

Clarification:

What should we return when needle is an empty string? This is a great question to ask during an interview.

+

For the purpose of this problem, we will return 0 when needle is an empty string. This is consistent to C’s strstr() and Java’s indexOf().

+

示例

Example 1:

+
Input: haystack = "hello", needle = "ll"
+Output: 2
+

Example 2:

+
Input: haystack = "aaaaa", needle = "bba"
+Output: -1
+

Example 3:

+
Input: haystack = "", needle = ""
+Output: 0
+ +

题解

字符串比较其实是写代码里永恒的主题,底层的编译器等处理肯定需要字符串对比,像 kmp 算法也是很厉害

+

code

public int strStr(String haystack, String needle) {
+        // 如果两个字符串都为空,返回 -1
+        if (haystack == null || needle == null) {
+            return -1;
+        }
+        // 如果 haystack 长度小于 needle 长度,返回 -1
+        if (haystack.length() < needle.length()) {
+            return -1;
+        }
+        // 如果 needle 为空字符串,返回 0
+        if (needle.equals("")) {
+            return 0;
+        }
+        // 如果两者相等,返回 0
+        if (haystack.equals(needle)) {
+            return 0;
+        }
+        int needleLength = needle.length();
+        int haystackLength = haystack.length();
+        for (int i = needleLength - 1; i <= haystackLength - 1; i++) {
+            // 比较 needle 最后一个字符,倒着比较稍微节省点时间
+            if (needle.charAt(needleLength - 1) == haystack.charAt(i)) {
+                // 如果needle 是 1 的话直接可以返回 i 作为位置了
+                if (needle.length() == 1) {
+                    return i;
+                }
+                boolean flag = true;
+                // 原来比的是 needle 的最后一个位置,然后这边从倒数第二个位置开始
+                int j = needle.length() - 2;
+                for (; j >= 0; j--) {
+                    // 这里的 i- (needleLength - j) + 1 ) 比较绕,其实是外循环的 i 表示当前 i 位置的字符跟 needle 最后一个字符
+                    // 相同,j 在上面的循环中--,对应的 haystack 也要在 i 这个位置 -- ,对应的位置就是 i - (needleLength - j) + 1
+                    if (needle.charAt(j) != haystack.charAt(i - (needleLength - j) + 1)) {
+                        flag = false;
+                        break;
+                    }
+                }
+                // 循环完了之后,如果 flag 为 true 说明 从 i 开始倒着对比都相同,但是这里需要起始位置,就需要
+                // i - needleLength + 1
+                if (flag) {
+                    return i - needleLength + 1;
+                }
+            }
+        }
+        // 这里表示未找到
+        return  -1;
+    }
]]>
+ + Java + leetcode + + + leetcode + java + 题解 + +
+ + Leetcode 021 合并两个有序链表 ( Merge Two Sorted Lists ) 题解分析 + /2021/10/07/Leetcode-021-%E5%90%88%E5%B9%B6%E4%B8%A4%E4%B8%AA%E6%9C%89%E5%BA%8F%E9%93%BE%E8%A1%A8-Merge-Two-Sorted-Lists-%E9%A2%98%E8%A7%A3%E5%88%86%E6%9E%90/ + 题目介绍

Merge two sorted linked lists and return it as a sorted list. The list should be made by splicing together the nodes of the first two lists.

+

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

+

示例 1

+
+

输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]

+
+

示例 2

+

输入: l1 = [], l2 = []
输出: []

+
+

示例 3

+

输入: l1 = [], l2 = [0]
输出: [0]

+
+

简要分析

这题是 Easy 的,看着也挺简单,两个链表进行合并,就是比较下大小,可能将就点的话最好就在两个链表中原地合并

+

题解代码

public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
+        // 下面两个if判断了入参的边界,如果其一为null,直接返回另一个就可以了
+        if (l1 == null) {
+            return l2;
+        }
         if (l2 == null) {
             return l1;
         }
@@ -3596,6 +3169,45 @@ Node *clone(Node *graph) {
         题解
       
   
+  
+    Leetcode 053 最大子序和 ( Maximum Subarray ) 题解分析
+    /2021/11/28/Leetcode-053-%E6%9C%80%E5%A4%A7%E5%AD%90%E5%BA%8F%E5%92%8C-Maximum-Subarray-%E9%A2%98%E8%A7%A3%E5%88%86%E6%9E%90/
+    题目介绍

Given an integer array nums, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.

+

A subarray is a contiguous part of an array.

+

示例

Example 1:

+
+

Input: nums = [-2,1,-3,4,-1,2,1,-5,4]
Output: 6
Explanation: [4,-1,2,1] has the largest sum = 6.

+
+

Example 2:

+
+

Input: nums = [1]
Output: 1

+
+

Example 3:

+
+

Input: nums = [5,4,-1,7,8]
Output: 23

+
+

说起来这个题其实非常有渊源,大学数据结构的第一个题就是这个,而最佳的算法就是传说中的 online 算法,就是遍历一次就完了,最基本的做法就是记下来所有的连续子数组,然后求出最大的那个。

+

代码

public int maxSubArray(int[] nums) {
+        int max = nums[0];
+        int sum = nums[0];
+        for (int i = 1; i < nums.length; i++) {
+            // 这里最重要的就是这一行了,其实就是如果前面的 sum 是小于 0 的,那么就不需要前面的 sum,反正加上了还不如不加大
+            sum = Math.max(nums[i], sum + nums[i]);
+            // max 是用来承载最大值的
+            max = Math.max(max, sum);
+        }
+        return max;
+    }
]]>
+ + Java + leetcode + + + leetcode + java + 题解 + +
Leetcode 104 二叉树的最大深度(Maximum Depth of Binary Tree) 题解分析 /2020/10/25/Leetcode-104-%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E6%9C%80%E5%A4%A7%E6%B7%B1%E5%BA%A6-Maximum-Depth-of-Binary-Tree-%E9%A2%98%E8%A7%A3%E5%88%86%E6%9E%90/ @@ -3648,196 +3260,82 @@ Node *clone(Node *graph) { - Leetcode 053 最大子序和 ( Maximum Subarray ) 题解分析 - /2021/11/28/Leetcode-053-%E6%9C%80%E5%A4%A7%E5%AD%90%E5%BA%8F%E5%92%8C-Maximum-Subarray-%E9%A2%98%E8%A7%A3%E5%88%86%E6%9E%90/ - 题目介绍

Given an integer array nums, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.

-

A subarray is a contiguous part of an array.

-

示例

Example 1:

-
-

Input: nums = [-2,1,-3,4,-1,2,1,-5,4]
Output: 6
Explanation: [4,-1,2,1] has the largest sum = 6.

-
-

Example 2:

-
-

Input: nums = [1]
Output: 1

-
-

Example 3:

-
-

Input: nums = [5,4,-1,7,8]
Output: 23

-
-

说起来这个题其实非常有渊源,大学数据结构的第一个题就是这个,而最佳的算法就是传说中的 online 算法,就是遍历一次就完了,最基本的做法就是记下来所有的连续子数组,然后求出最大的那个。

-

代码

public int maxSubArray(int[] nums) {
-        int max = nums[0];
-        int sum = nums[0];
-        for (int i = 1; i < nums.length; i++) {
-            // 这里最重要的就是这一行了,其实就是如果前面的 sum 是小于 0 的,那么就不需要前面的 sum,反正加上了还不如不加大
-            sum = Math.max(nums[i], sum + nums[i]);
-            // max 是用来承载最大值的
-            max = Math.max(max, sum);
+    Leetcode 105 从前序与中序遍历序列构造二叉树(Construct Binary Tree from Preorder and Inorder Traversal) 题解分析
+    /2020/12/13/Leetcode-105-%E4%BB%8E%E5%89%8D%E5%BA%8F%E4%B8%8E%E4%B8%AD%E5%BA%8F%E9%81%8D%E5%8E%86%E5%BA%8F%E5%88%97%E6%9E%84%E9%80%A0%E4%BA%8C%E5%8F%89%E6%A0%91-Construct-Binary-Tree-from-Preorder-and-Inorder-Traversal-%E9%A2%98%E8%A7%A3%E5%88%86%E6%9E%90/
+    题目介绍

Given preorder and inorder traversal of a tree, construct the binary tree.
给定一棵树的前序和中序遍历,构造出一棵二叉树

+

注意

You may assume that duplicates do not exist in the tree.
你可以假设树中没有重复的元素。(PS: 不然就没法做了呀)

+

例子:

preorder = [3,9,20,15,7]
+inorder = [9,3,15,20,7]
+

返回的二叉树

+
  3
+ / \
+9  20
+  /  \
+ 15   7
+ + +

简要分析

看到这个题可以想到一个比较常规的解法就是递归拆树,前序就是根左右,中序就是左根右,然后就是通过前序已经确定的根在中序中找到,然后去划分左右子树,这个例子里是 3,找到中序中的位置,那么就可以确定,9 是左子树,15,20,7是右子树,然后对应的可以根据左右子树的元素数量在前序中划分左右子树,再继续递归就行

+
class Solution {
+    public TreeNode buildTree(int[] preorder, int[] inorder) {
+      // 获取下数组长度
+        int n = preorder.length;
+        // 排除一下异常和边界
+        if (n != inorder.length) {
+            return null;
         }
-        return max;
-    }
]]>
+ if (n == 0) { + return null; + } + if (n == 1) { + return new TreeNode(preorder[0]); + } + // 获得根节点 + TreeNode node = new TreeNode(preorder[0]); + int pos = 0; + // 找到中序中的位置 + for (int i = 0; i < inorder.length; i++) { + if (node.val == inorder[i]) { + pos = i; + break; + } + } + // 划分左右再进行递归,注意下`Arrays.copyOfRange`的用法 + node.left = buildTree(Arrays.copyOfRange(preorder, 1, pos + 1), Arrays.copyOfRange(inorder, 0, pos)); + node.right = buildTree(Arrays.copyOfRange(preorder, pos + 1, n), Arrays.copyOfRange(inorder, pos + 1, n)); + return node; + } +}
]]>
Java leetcode + Binary Tree + java + Binary Tree + DFS leetcode java + Binary Tree + 二叉树 题解 + 递归 + Preorder Traversal + Inorder Traversal + 前序 + 中序
- Leetcode 028 实现 strStr() ( Implement strStr() ) 题解分析 - /2021/10/31/Leetcode-028-%E5%AE%9E%E7%8E%B0-strStr-Implement-strStr-%E9%A2%98%E8%A7%A3%E5%88%86%E6%9E%90/ - 题目介绍

Implement strStr().

-

Return the index of the first occurrence of needle in haystack, or -1 if needle is not part of haystack.

-

Clarification:

What should we return when needle is an empty string? This is a great question to ask during an interview.

-

For the purpose of this problem, we will return 0 when needle is an empty string. This is consistent to C’s strstr() and Java’s indexOf().

-

示例

Example 1:

-
Input: haystack = "hello", needle = "ll"
-Output: 2
-

Example 2:

-
Input: haystack = "aaaaa", needle = "bba"
-Output: -1
-

Example 3:

-
Input: haystack = "", needle = ""
-Output: 0
- -

题解

字符串比较其实是写代码里永恒的主题,底层的编译器等处理肯定需要字符串对比,像 kmp 算法也是很厉害

-

code

public int strStr(String haystack, String needle) {
-        // 如果两个字符串都为空,返回 -1
-        if (haystack == null || needle == null) {
-            return -1;
-        }
-        // 如果 haystack 长度小于 needle 长度,返回 -1
-        if (haystack.length() < needle.length()) {
-            return -1;
-        }
-        // 如果 needle 为空字符串,返回 0
-        if (needle.equals("")) {
-            return 0;
-        }
-        // 如果两者相等,返回 0
-        if (haystack.equals(needle)) {
-            return 0;
-        }
-        int needleLength = needle.length();
-        int haystackLength = haystack.length();
-        for (int i = needleLength - 1; i <= haystackLength - 1; i++) {
-            // 比较 needle 最后一个字符,倒着比较稍微节省点时间
-            if (needle.charAt(needleLength - 1) == haystack.charAt(i)) {
-                // 如果needle 是 1 的话直接可以返回 i 作为位置了
-                if (needle.length() == 1) {
-                    return i;
-                }
-                boolean flag = true;
-                // 原来比的是 needle 的最后一个位置,然后这边从倒数第二个位置开始
-                int j = needle.length() - 2;
-                for (; j >= 0; j--) {
-                    // 这里的 i- (needleLength - j) + 1 ) 比较绕,其实是外循环的 i 表示当前 i 位置的字符跟 needle 最后一个字符
-                    // 相同,j 在上面的循环中--,对应的 haystack 也要在 i 这个位置 -- ,对应的位置就是 i - (needleLength - j) + 1
-                    if (needle.charAt(j) != haystack.charAt(i - (needleLength - j) + 1)) {
-                        flag = false;
-                        break;
-                    }
-                }
-                // 循环完了之后,如果 flag 为 true 说明 从 i 开始倒着对比都相同,但是这里需要起始位置,就需要
-                // i - needleLength + 1
-                if (flag) {
-                    return i - needleLength + 1;
-                }
-            }
-        }
-        // 这里表示未找到
-        return  -1;
-    }
]]>
- - Java - leetcode - - - leetcode - java - 题解 - -
- - Leetcode 105 从前序与中序遍历序列构造二叉树(Construct Binary Tree from Preorder and Inorder Traversal) 题解分析 - /2020/12/13/Leetcode-105-%E4%BB%8E%E5%89%8D%E5%BA%8F%E4%B8%8E%E4%B8%AD%E5%BA%8F%E9%81%8D%E5%8E%86%E5%BA%8F%E5%88%97%E6%9E%84%E9%80%A0%E4%BA%8C%E5%8F%89%E6%A0%91-Construct-Binary-Tree-from-Preorder-and-Inorder-Traversal-%E9%A2%98%E8%A7%A3%E5%88%86%E6%9E%90/ - 题目介绍

Given preorder and inorder traversal of a tree, construct the binary tree.
给定一棵树的前序和中序遍历,构造出一棵二叉树

-

注意

You may assume that duplicates do not exist in the tree.
你可以假设树中没有重复的元素。(PS: 不然就没法做了呀)

-

例子:

preorder = [3,9,20,15,7]
-inorder = [9,3,15,20,7]
-

返回的二叉树

-
  3
- / \
-9  20
-  /  \
- 15   7
- - -

简要分析

看到这个题可以想到一个比较常规的解法就是递归拆树,前序就是根左右,中序就是左根右,然后就是通过前序已经确定的根在中序中找到,然后去划分左右子树,这个例子里是 3,找到中序中的位置,那么就可以确定,9 是左子树,15,20,7是右子树,然后对应的可以根据左右子树的元素数量在前序中划分左右子树,再继续递归就行

-
class Solution {
-    public TreeNode buildTree(int[] preorder, int[] inorder) {
-      // 获取下数组长度
-        int n = preorder.length;
-        // 排除一下异常和边界
-        if (n != inorder.length) {
-            return null;
-        }
-        if (n == 0) {
-            return null;
-        }
-        if (n == 1) {
-            return new TreeNode(preorder[0]);
-        }
-        // 获得根节点
-        TreeNode node = new TreeNode(preorder[0]);
-        int pos = 0;
-        // 找到中序中的位置
-        for (int i = 0; i < inorder.length; i++) {
-            if (node.val == inorder[i]) {
-                pos = i;
-                break;
-            }
-        }
-        // 划分左右再进行递归,注意下`Arrays.copyOfRange`的用法
-        node.left = buildTree(Arrays.copyOfRange(preorder, 1, pos + 1), Arrays.copyOfRange(inorder, 0, pos));
-        node.right = buildTree(Arrays.copyOfRange(preorder, pos + 1, n), Arrays.copyOfRange(inorder, pos + 1, n));
-        return node;
-    }
-}
]]>
- - Java - leetcode - Binary Tree - java - Binary Tree - DFS - - - leetcode - java - Binary Tree - 二叉树 - 题解 - 递归 - Preorder Traversal - Inorder Traversal - 前序 - 中序 - -
- - Leetcode 1115 交替打印 FooBar ( Print FooBar Alternately *Medium* ) 题解分析 - /2022/05/01/Leetcode-1115-%E4%BA%A4%E6%9B%BF%E6%89%93%E5%8D%B0-FooBar-Print-FooBar-Alternately-Medium-%E9%A2%98%E8%A7%A3%E5%88%86%E6%9E%90/ - 无聊想去 roll 一题就看到了有并发题,就找到了这题,其实一眼看我的想法也是用信号量,但是用 condition 应该也是可以处理的,不过这类问题好像本地有点难调,因为它好像是抽取代码执行的,跟直观的逻辑比较不一样
Suppose you are given the following code:

-
class FooBar {
-  public void foo() {
-    for (int i = 0; i < n; i++) {
-      print("foo");
-    }
-  }
+    Leetcode 1115 交替打印 FooBar ( Print FooBar Alternately *Medium* ) 题解分析
+    /2022/05/01/Leetcode-1115-%E4%BA%A4%E6%9B%BF%E6%89%93%E5%8D%B0-FooBar-Print-FooBar-Alternately-Medium-%E9%A2%98%E8%A7%A3%E5%88%86%E6%9E%90/
+    无聊想去 roll 一题就看到了有并发题,就找到了这题,其实一眼看我的想法也是用信号量,但是用 condition 应该也是可以处理的,不过这类问题好像本地有点难调,因为它好像是抽取代码执行的,跟直观的逻辑比较不一样
Suppose you are given the following code:

+
class FooBar {
+  public void foo() {
+    for (int i = 0; i < n; i++) {
+      print("foo");
+    }
+  }
 
   public void bar() {
     for (int i = 0; i < n; i++) {
@@ -3949,118 +3447,209 @@ inorder = [9,3,15,20,7]
-

https://img.nicksxs.com/uPic/bRMvlR.png

-

可以看到变成了轻量级锁,在线程没有争抢,只是进行了切换,就会使用轻量级锁,当两个线程在竞争了,就又会升级成重量级锁

-
public class ObjectHeaderDemo {
-    public static void main(String[] args) throws InterruptedException {
-        TimeUnit.SECONDS.sleep(5);
-        L l = new L();
-        System.out.println(ClassLayout.parseInstance(l).toPrintable());
-        synchronized (l) {
-            System.out.println("1\n" + ClassLayout.parseInstance(l).toPrintable());
+

https://img.nicksxs.com/uPic/bRMvlR.png

+

可以看到变成了轻量级锁,在线程没有争抢,只是进行了切换,就会使用轻量级锁,当两个线程在竞争了,就又会升级成重量级锁

+
public class ObjectHeaderDemo {
+    public static void main(String[] args) throws InterruptedException {
+        TimeUnit.SECONDS.sleep(5);
+        L l = new L();
+        System.out.println(ClassLayout.parseInstance(l).toPrintable());
+        synchronized (l) {
+            System.out.println("1\n" + ClassLayout.parseInstance(l).toPrintable());
+        }
+        Thread thread1 = new Thread() {
+            @Override
+            public void run() {
+                try {
+                    TimeUnit.SECONDS.sleep(5L);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+                synchronized (l) {
+                    System.out.println("thread1 获取锁成功");
+                    System.out.println(ClassLayout.parseInstance(l).toPrintable());
+                    try {
+                        TimeUnit.SECONDS.sleep(5L);
+                    } catch (InterruptedException e) {
+                        e.printStackTrace();
+                    }
+                }
+            }
+        };
+        Thread thread2 = new Thread() {
+            @Override
+            public void run() {
+                try {
+                    TimeUnit.SECONDS.sleep(5L);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+                synchronized (l) {
+                    System.out.println("thread2 获取锁成功");
+                    System.out.println(ClassLayout.parseInstance(l).toPrintable());
+                }
+            }
+        };
+        thread1.start();
+        thread2.start();
+    }
+}
+
+class L {
+    private boolean myboolean = true;
+}
+ +

https://img.nicksxs.com/uPic/LMzMtR.png

+

可以看到变成了重量级锁。

+]]> + + Java + + + Java + Synchronized + 偏向锁 + 轻量级锁 + 重量级锁 + 自旋 + + + + 聊聊 Dubbo 的 SPI + /2020/05/31/%E8%81%8A%E8%81%8A-Dubbo-%E7%9A%84-SPI/ + SPI全称是Service Provider Interface,咋眼看跟api是不是有点相似,api是application interface,这两个其实在某些方面有类似的地方,也有蛮大的区别,比如我们基于 dubbo 的微服务,一般我们可以提供服务,然后非泛化调用的话,我们可以把 api 包提供给应用调用方,他们根据接口签名传对应参数并配置好对应的服务发现如 zk 等就可以调用我们的服务了,然后 spi 会有点类似但是是反过来的关系,相当于是一种规范,比如我约定完成这个功能需要两个有两个接口,一个是连接的,一个是断开的,其实就可以用 jdbc 的驱动举例,比较老套了,然后各个厂家去做具体的实现吧,到时候根据我接口的全限定名的文件来加载实际的实现类,然后运行的时候调用对应实现类的方法就完了

+

3sKdpg

+

看上面的图,java.sql.Driver就是 spi,对应在classpath 的 META-INF/services 目录下的这个文件,里边的内容就是具体的实现类

+

1590735097909

+

简单介绍了 Java的 SPI,再来说说 dubbo 的,dubbo 中为啥要用 SPI 呢,主要是为了框架的可扩展性和性能方面的考虑,比如协议层 dubbo 默认使用 dubbo 协议,同时也支持很多其他协议,也支持用户自己实现协议,那么跟 Java 的 SPI 会有什么区别呢,我们也来看个文件

+

bqxWMp

+

是不是看着很想,又有点不一样,在 Java 的 SPI 配置文件里每一行只有一个实现类的全限定名,在 Dubbo的 SPI配置文件中是 key=value 的形式,我们只需要对应的 key 就能加载对应的实现,

+
/**
+     * 返回指定名字的扩展。如果指定名字的扩展不存在,则抛异常 {@link IllegalStateException}.
+     *
+     * @param name
+     * @return
+     */
+	@SuppressWarnings("unchecked")
+	public T getExtension(String name) {
+		if (name == null || name.length() == 0)
+		    throw new IllegalArgumentException("Extension name == null");
+		if ("true".equals(name)) {
+		    return getDefaultExtension();
+		}
+		Holder<Object> holder = cachedInstances.get(name);
+		if (holder == null) {
+		    cachedInstances.putIfAbsent(name, new Holder<Object>());
+		    holder = cachedInstances.get(name);
+		}
+		Object instance = holder.get();
+		if (instance == null) {
+		    synchronized (holder) {
+	            instance = holder.get();
+	            if (instance == null) {
+	                instance = createExtension(name);
+	                holder.set(instance);
+	            }
+	        }
+		}
+		return (T) instance;
+	}
+

这里其实就可以看出来第二个不同点了,就是这个cachedInstances,第一个是不用像 Java 原生的 SPI 那样去遍历加载对应的服务类,只需要通过 key 去寻找,并且寻找的时候会先从缓存的对象里去取,还有就是注意下这里的 DCL(double check lock)

+
@SuppressWarnings("unchecked")
+    private T createExtension(String name) {
+        Class<?> clazz = getExtensionClasses().get(name);
+        if (clazz == null) {
+            throw findException(name);
+        }
+        try {
+            T instance = (T) EXTENSION_INSTANCES.get(clazz);
+            if (instance == null) {
+                EXTENSION_INSTANCES.putIfAbsent(clazz, (T) clazz.newInstance());
+                instance = (T) EXTENSION_INSTANCES.get(clazz);
+            }
+            injectExtension(instance);
+            Set<Class<?>> wrapperClasses = cachedWrapperClasses;
+            if (wrapperClasses != null && wrapperClasses.size() > 0) {
+                for (Class<?> wrapperClass : wrapperClasses) {
+                    instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
+                }
+            }
+            return instance;
+        } catch (Throwable t) {
+            throw new IllegalStateException("Extension instance(name: " + name + ", class: " +
+                    type + ")  could not be instantiated: " + t.getMessage(), t);
+        }
+    }
+

然后就是创建扩展了,这里如果 wrapperClasses 就会遍历生成wrapper实例,并做 setter 依赖注入,但是这里cachedWrapperClasses的来源还是有点搞不清楚,得再看下 com.alibaba.dubbo.common.extension.ExtensionLoader#loadFile的具体逻辑
又看了遍新的代码,这个函数被抽出来了

+
/**
+    * test if clazz is a wrapper class
+    * <p>
+    * which has Constructor with given class type as its only argument
+    */
+   private boolean isWrapperClass(Class<?> clazz) {
+       try {
+           clazz.getConstructor(type);
+           return true;
+       } catch (NoSuchMethodException e) {
+           return false;
+       }
+   }
+

是否是 wrapperClass 其实就看构造函数的。

+]]>
+ + Java + Dubbo + RPC + SPI + Dubbo + SPI + + + Java + Dubbo + RPC + SPI + +
+ + 聊聊 Java 的 equals 和 hashCode 方法 + /2021/01/03/%E8%81%8A%E8%81%8A-Java-%E7%9A%84-equals-%E5%92%8C-hashCode-%E6%96%B9%E6%B3%95/ + Java 中的这个话题也是比较常遇到的,关于这块原先也是比较忽略的,但是仔细想想又有点遗忘了就在这里记一下
简单看下代码
java.lang.Object#equals

+
public boolean equals(Object obj) {
+        return (this == obj);
+    }
+

对于所有对象的父类,equals 方法其实对比的就是对象的地址,也就是是否是同一个对象,试想如果像 Integer 或者 String 这种,我们没有重写 equals,那其实就等于是在用==,可能就没法达到我们的目的,所以像 String 这种常用的 jdk 类都是默认重写了
java.lang.String#equals

+
public boolean equals(Object anObject) {
+        if (this == anObject) {
+            return true;
+        }
+        if (anObject instanceof String) {
+            String anotherString = (String)anObject;
+            int n = value.length;
+            if (n == anotherString.value.length) {
+                char v1[] = value;
+                char v2[] = anotherString.value;
+                int i = 0;
+                while (n-- != 0) {
+                    if (v1[i] != v2[i])
+                        return false;
+                    i++;
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+

然后呢就是为啥一些书或者 effective java 中写了 equalshashCode 要一起重写,这里涉及到当对象作为 HashMapkey 的时候
首先 HashMap 会使用 hashCode 去判断是否在同一个槽里,然后在通过 equals 去判断是否是同一个 key,是的话就替换,不是的话就链表接下去,如果不重写 hashCode 的话,默认的 objecthashCodenative 方法,根据对象的地址生成的,这样其实对象的值相同的话,因为地址不同,HashMap 也会出现异常,所以需要重写,同时也需要重写 equals 方法,才能确认是同一个 key,而不是落在同一个槽的不同 key.

+]]>
+ + java + + + java + +
+ + 聊聊 Java 的类加载机制一 + /2020/11/08/%E8%81%8A%E8%81%8A-Java-%E7%9A%84%E7%B1%BB%E5%8A%A0%E8%BD%BD%E6%9C%BA%E5%88%B6/ + 一说到这个主题,想到的应该是双亲委派模型,不过讲的包括但不限于这个,主要内容是参考深入理解 Java 虚拟机书中的介绍,
一个类型的生命周期包含了七个阶段,加载,验证,准备,解析,初始化,使用,卸载。

+
    +
  • 加载

  • +
+
    +
  1. 通过一个类的全限定名来获取定义此类的二进制字节流
  2. +
  3. 将这个字节流代表的静态存储结构转化为方法区的运行时数据结构
  4. +
  5. 在内存中生成了一个代表这个类的 java.lang.Class 对象,作为方法区这个类的各种数据的访问入口
  6. +
+
    +
  • 验证

  • +
+
    +
  1. 文件格式验证
  2. +
  3. 元数据验证
  4. +
  5. 字节码验证
  6. +
  7. 符号引用验证
  8. +
+
    +
  • 准备

    准备阶段是正式为类中定义的变量(即静态变量,被static修饰的变量)分配内存并设置类变量初始值的阶段

    +
  • +
  • 解析

    解析阶段是 Java 虚拟机将常量池内的符号引用替换为直接引用的过程

    +
  • +
+

以上验证准备解析 三个阶段又合称为链接阶段,链接阶段要做的是将加载到JVM中的二进制字节流的类数据信息合并到JVM的运行时状态中。

+
    +
  • 初始化

    类的初始化阶段是类加载过程的最后一个步骤,也是除了自定义类加载器之外将主动权交给了应用程序,其实就是执行类构造器()方法的过程,()并不是我们在 Java 代码中直接编写的方法,它是 Javac编译器的自动生成物,()方法是由编译器自动收集类中的所有类变量的复制动作和静态句块(static{}块)中的语句合并产生的,编译器收集的顺序是由语句在原文件中出现的顺序决定的,静态语句块中只能访问定义在静态语句块之前的变量,定义在它之后的变量,在前面的静态语句块可以复制,但是不能访问,同时还要保证父类的执行先于子类,然后保证多线程下的并发问题
  • +
+

最终,方法区会存储当前类类信息,包括类的静态变量、类初始化代码(定义静态变量时的赋值语句 和 静态初始化代码块)、实例变量定义、实例初始化代码(定义实例变量时的赋值语句实例代码块和构造方法)和实例方法,还有父类的类信息引用。

+]]>
+ + Java + 类加载 + +
+ + 聊聊 Java 中绕不开的 Synchronized 关键字 + /2021/06/20/%E8%81%8A%E8%81%8A-Java-%E4%B8%AD%E7%BB%95%E4%B8%8D%E5%BC%80%E7%9A%84-Synchronized-%E5%85%B3%E9%94%AE%E5%AD%97/ + Synchronized 关键字在 Java 的并发体系里也是非常重要的一个内容,首先比较常规的是知道它使用的方式,可以锁对象,可以锁代码块,也可以锁方法,看一个简单的 demo

+
public class SynchronizedDemo {
+
+    public static void main(String[] args) {
+        SynchronizedDemo synchronizedDemo = new SynchronizedDemo();
+        synchronizedDemo.lockMethod();
+    }
+
+    public synchronized void lockMethod() {
+        System.out.println("here i'm locked");
+    }
+
+    public void lockSynchronizedDemo() {
+        synchronized (this) {
+            System.out.println("here lock class");
         }
-        Thread thread1 = new Thread() {
-            @Override
-            public void run() {
-                try {
-                    TimeUnit.SECONDS.sleep(5L);
-                } catch (InterruptedException e) {
-                    e.printStackTrace();
-                }
-                synchronized (l) {
-                    System.out.println("thread1 获取锁成功");
-                    System.out.println(ClassLayout.parseInstance(l).toPrintable());
-                    try {
-                        TimeUnit.SECONDS.sleep(5L);
-                    } catch (InterruptedException e) {
-                        e.printStackTrace();
-                    }
-                }
-            }
-        };
-        Thread thread2 = new Thread() {
-            @Override
-            public void run() {
-                try {
-                    TimeUnit.SECONDS.sleep(5L);
-                } catch (InterruptedException e) {
-                    e.printStackTrace();
-                }
-                synchronized (l) {
-                    System.out.println("thread2 获取锁成功");
-                    System.out.println(ClassLayout.parseInstance(l).toPrintable());
-                }
-            }
-        };
-        thread1.start();
-        thread2.start();
     }
-}
+}
-class L { - private boolean myboolean = true; -}
+

然后来查看反编译结果,其实代码(日光)之下并无新事,即使是完全不懂的也可以通过一些词义看出一些意义

+
  Last modified 2021620; size 729 bytes
+  MD5 checksum dd9c529863bd7ff839a95481db578ad9
+  Compiled from "SynchronizedDemo.java"
+public class SynchronizedDemo
+  minor version: 0
+  major version: 53
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #2                          // SynchronizedDemo
+  super_class: #9                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 4, attributes: 1
+Constant pool:
+   #1 = Methodref          #9.#22         // java/lang/Object."<init>":()V
+   #2 = Class              #23            // SynchronizedDemo
+   #3 = Methodref          #2.#22         // SynchronizedDemo."<init>":()V
+   #4 = Methodref          #2.#24         // SynchronizedDemo.lockMethod:()V
+   #5 = Fieldref           #25.#26        // java/lang/System.out:Ljava/io/PrintStream;
+   #6 = String             #27            // here i\'m locked
+   #7 = Methodref          #28.#29        // java/io/PrintStream.println:(Ljava/lang/String;)V
+   #8 = String             #30            // here lock class
+   #9 = Class              #31            // java/lang/Object
+  #10 = Utf8               <init>
+  #11 = Utf8               ()V
+  #12 = Utf8               Code
+  #13 = Utf8               LineNumberTable
+  #14 = Utf8               main
+  #15 = Utf8               ([Ljava/lang/String;)V
+  #16 = Utf8               lockMethod
+  #17 = Utf8               lockSynchronizedDemo
+  #18 = Utf8               StackMapTable
+  #19 = Class              #32            // java/lang/Throwable
+  #20 = Utf8               SourceFile
+  #21 = Utf8               SynchronizedDemo.java
+  #22 = NameAndType        #10:#11        // "<init>":()V
+  #23 = Utf8               SynchronizedDemo
+  #24 = NameAndType        #16:#11        // lockMethod:()V
+  #25 = Class              #33            // java/lang/System
+  #26 = NameAndType        #34:#35        // out:Ljava/io/PrintStream;
+  #27 = Utf8               here i\'m locked
+  #28 = Class              #36            // java/io/PrintStream
+  #29 = NameAndType        #37:#38        // println:(Ljava/lang/String;)V
+  #30 = Utf8               here lock class
+  #31 = Utf8               java/lang/Object
+  #32 = Utf8               java/lang/Throwable
+  #33 = Utf8               java/lang/System
+  #34 = Utf8               out
+  #35 = Utf8               Ljava/io/PrintStream;
+  #36 = Utf8               java/io/PrintStream
+  #37 = Utf8               println
+  #38 = Utf8               (Ljava/lang/String;)V
+{
+  public SynchronizedDemo();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
+         4: return
+      LineNumberTable:
+        line 5: 0
 
-

https://img.nicksxs.com/uPic/LMzMtR.png

-

可以看到变成了重量级锁。

+ public static void main(java.lang.String[]); + descriptor: ([Ljava/lang/String;)V + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=2, locals=2, args_size=1 + 0: new #2 // class SynchronizedDemo + 3: dup + 4: invokespecial #3 // Method "<init>":()V + 7: astore_1 + 8: aload_1 + 9: invokevirtual #4 // Method lockMethod:()V + 12: return + LineNumberTable: + line 8: 0 + line 9: 8 + line 10: 12 + + public synchronized void lockMethod(); + descriptor: ()V + flags: (0x0021) ACC_PUBLIC, ACC_SYNCHRONIZED + Code: + stack=2, locals=1, args_size=1 + 0: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream; + 3: ldc #6 // String here i\'m locked + 5: invokevirtual #7 // Method java/io/PrintStream.println:(Ljava/lang/String;)V + 8: return + LineNumberTable: + line 13: 0 + line 14: 8 + + public void lockSynchronizedDemo(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=2, locals=3, args_size=1 + 0: aload_0 + 1: dup + 2: astore_1 + 3: monitorenter + 4: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream; + 7: ldc #8 // String here lock class + 9: invokevirtual #7 // Method java/io/PrintStream.println:(Ljava/lang/String;)V + 12: aload_1 + 13: monitorexit + 14: goto 22 + 17: astore_2 + 18: aload_1 + 19: monitorexit + 20: aload_2 + 21: athrow + 22: return + Exception table: + from to target type + 4 14 17 any + 17 20 17 any + LineNumberTable: + line 17: 0 + line 18: 4 + line 19: 12 + line 20: 22 + StackMapTable: number_of_entries = 2 + frame_type = 255 /* full_frame */ + offset_delta = 17 + locals = [ class SynchronizedDemo, class java/lang/Object ] + stack = [ class java/lang/Throwable ] + frame_type = 250 /* chop */ + offset_delta = 4 +} +SourceFile: "SynchronizedDemo.java"
+ +

其中lockMethod中可以看到是通过 ACC_SYNCHRONIZED flag 来标记是被 synchronized 修饰,前面的 ACC 应该是 access 的意思,并且通过 ACC_PUBLIC 也可以看出来他们是同一类访问权限关键字来控制的,而修饰类则是通过3: monitorenter13: monitorexit来控制并发,这个是原来就知道,后来看了下才知道修饰方法是不一样的,但是在前期都比较诟病是 synchronized 的性能,像 monitor 也是通过操作系统的mutex lock互斥锁来实现的,相对是比较重的锁,于是在 JDK 1.6 之后对 synchronized 做了一系列优化,包括偏向锁,轻量级锁,并且包括像 ConcurrentHashMap 这类并发集合都有在使用 synchronized 关键字配合 cas 来做并发保护,

+

jdk 对于 synchronized 的优化主要在于多重状态锁的升级,最初会使用偏向锁,当一个线程访问同步块并获取锁时,会在对象头和栈帧中的锁记录里存储锁偏向的线程ID,以后该线程在进入和退出同步块时不需要进行CAS操作来加锁和解锁,只需简单地测试一下对象头的Mark Word里是否存储着指向当前线程的偏向锁。引入偏向锁是为了在无多线程竞争的情况下尽量减少不必要的轻量级锁执行路径,因为轻量级锁的获取及释放依赖多次CAS原子指令,而偏向锁只需要在置换ThreadID的时候依赖一次CAS原子指令(由于一旦出现多线程竞争的情况就必须撤销偏向锁,所以偏向锁的撤销操作的性能损耗必须小于节省下来的CAS原子指令的性能消耗)。
而当出现线程尝试进入同步块时发现已有偏向锁,并且是其他线程时,会将锁升级成轻量级锁,并且自旋尝试获取锁,如果自旋成功则表示获取轻量级锁成功,否则将会升级成重量级锁进行阻塞,当然这里具体的还很复杂,说的比较浅薄主体还是想将原先的阻塞互斥锁进行轻量化,区分特殊情况进行加锁。

]]>
Java @@ -16087,63 +15800,376 @@ public Result invoke(final Invocation invocation) throws RpcException { "GC task thread#1 (ParallelGC)" os_prio=31 tid=0x00007fc9de003800 nid=0x2a03 runnable -"GC task thread#2 (ParallelGC)" os_prio=31 tid=0x00007fc9df002000 nid=0x5403 runnable +"GC task thread#2 (ParallelGC)" os_prio=31 tid=0x00007fc9df002000 nid=0x5403 runnable + +"GC task thread#3 (ParallelGC)" os_prio=31 tid=0x00007fc9df002800 nid=0x5203 runnable + +"VM Periodic Task Thread" os_prio=31 tid=0x00007fc9df11a800 nid=0x3a03 waiting on condition + +JNI global references: 1087 + + +Found one Java-level deadlock: +============================= +"mythread2": + waiting for ownable synchronizer 0x000000076f5d4330, (a java.util.concurrent.locks.ReentrantLock$NonfairSync), + which is held by "mythread1" +"mythread1": + waiting for ownable synchronizer 0x000000076f5d4360, (a java.util.concurrent.locks.ReentrantLock$NonfairSync), + which is held by "mythread2" + +Java stack information for the threads listed above: +=================================================== +"mythread2": + at sun.misc.Unsafe.park(Native Method) + - parking to wait for <0x000000076f5d4330> (a java.util.concurrent.locks.ReentrantLock$NonfairSync) + at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175) + at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836) + at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870) + at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199) + at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209) + at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285) + at com.nicksxs.thread_dump_demo.ThreadDumpDemoApplication$2.run(ThreadDumpDemoApplication.java:34) +"mythread1": + at sun.misc.Unsafe.park(Native Method) + - parking to wait for <0x000000076f5d4360> (a java.util.concurrent.locks.ReentrantLock$NonfairSync) + at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175) + at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836) + at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870) + at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199) + at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209) + at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285) + at com.nicksxs.thread_dump_demo.ThreadDumpDemoApplication$1.run(ThreadDumpDemoApplication.java:22) + +Found 1 deadlock.
+

前面的信息其实上次就看过了,后面就可以发现有个死锁了,

上面比较长,把主要的截出来,就是这边的,这点就很强大了。

+

jmap

惯例还是看一下帮助信息

这个相对命令比较多,不过因为现在 dump 下来我们可能会用文件模式,然后将文件下载下来使用 mat 进行分析,所以可以使用
jmap -dump:live,format=b,file=heap.bin <pid>
命令照着上面看的就是打印活着的对象,然后以二进制格式,文件名叫 heap.bin 然后最后就是进程 id,打印出来以后可以用 mat 打开

这样就可以很清晰的看到应用里的各种信息,jmap 直接在命令中还可以看很多信息,比如使用jmap -histo <pid>打印对象的实例数和对象占用的内存

jmap -finalizerinfo <pid> 打印正在等候回收的对象

+

小tips

对于一些应用内存已经占满了,jstack 和 jmap 可能会连不上的情况,可以使用-F参数强制打印线程或者 dump 文件,但是要注意这两者使用的用户必须与 java 进程启动用户一致,并且使用的 jdk 也要一致

+]]> + + Java + Thread dump + 问题排查 + 工具 + + + Java + JPS + JStack + JMap + + + + 聊聊 Java 的类加载机制二 + /2021/06/13/%E8%81%8A%E8%81%8A-Java-%E7%9A%84%E7%B1%BB%E5%8A%A0%E8%BD%BD%E6%9C%BA%E5%88%B6%E4%BA%8C/ + 类加载器

类加载机制中说来说去其实也逃不开类加载器这个话题,我们就来说下类加载器这个话题,Java 在 jdk1.2 以后开始有了
Java 虚拟机设计团队有意把加载阶段中的“通过一个类的全限定名来获取描述该类的二进制字节流”这个动作放到 Java 虚拟机外部去实现,以便让应用程序自己去决定如何去获取所需的类。实现这个动作的代码被称为“类加载器”(Class Loader).
其实在 Java 中类加载器有一个很常用的作用,比如一个类的唯一性,其实是由加载它的类加载器和这个类一起来确定这个类在虚拟机的唯一性,这里也参考下周志明书里的例子

+
public class ClassLoaderTest {
+
+    public static void main(String[] args) throws Exception {
+        ClassLoader myLoader = new ClassLoader() {
+            @Override
+            public Class<?> loadClass(String name) throws ClassNotFoundException {
+                try {
+                    String fileName = name.substring(name.lastIndexOf(".") + 1) + ".class";
+                    InputStream is = getClass().getResourceAsStream(fileName);
+                    if (is == null) {
+                        return super.loadClass(name);
+                    }
+                    byte[] b = new byte[is.available()];
+                    is.read(b);
+                    return defineClass(name, b, 0, b.length);
+                } catch (IOException e) {
+                    throw new ClassNotFoundException(name);
+                }
+            }
+        };
+        Object object = myLoader.loadClass("com.nicksxs.demo.ClassLoaderTest").newInstance();
+        System.out.println(object.getClass());
+        System.out.println(object instanceof ClassLoaderTest);
+    }
+}
+

可以看下结果

这里说明了当一个是由虚拟机的应用程序类加载器所加载的和另一个由自己写的自定义类加载器加载的,虽然是同一个类,但是 instanceof 的结果就是 false 的

+

双亲委派

自 JDK1.2 以来,Java 一直有些三层类加载器、双亲委派的类加载架构

+

启动类加载器

首先是启动类加载器,Bootstrap Class Loader,这个类加载器负责加载放在\lib目录,或者被-Xbootclasspath参数所指定的路径中存放的,而且是Java 虚拟机能够识别的(按照文件名识别,如 rt.jar、tools.jar,名字不符合的类库即使放在 lib 目录中,也不会被加载)类库加载到虚拟机的内存中,启动类加载器无法被 Java 程序直接引用,用户在编写自定义类加载器时,如果需要把家在请求为派给引导类加载器去处理,那直接使用 null 代替即可,可以看下 java.lang.ClassLoader.getClassLoader()方法的代码片段

+
/**
+     * Returns the class loader for the class.  Some implementations may use
+     * null to represent the bootstrap class loader. This method will return
+     * null in such implementations if this class was loaded by the bootstrap
+     * class loader.
+     *
+     * <p> If a security manager is present, and the caller's class loader is
+     * not null and the caller's class loader is not the same as or an ancestor of
+     * the class loader for the class whose class loader is requested, then
+     * this method calls the security manager's {@code checkPermission}
+     * method with a {@code RuntimePermission("getClassLoader")}
+     * permission to ensure it's ok to access the class loader for the class.
+     *
+     * <p>If this object
+     * represents a primitive type or void, null is returned.
+     *
+     * @return  the class loader that loaded the class or interface
+     *          represented by this object.
+     * @throws SecurityException
+     *    if a security manager exists and its
+     *    {@code checkPermission} method denies
+     *    access to the class loader for the class.
+     * @see java.lang.ClassLoader
+     * @see SecurityManager#checkPermission
+     * @see java.lang.RuntimePermission
+     */
+    @CallerSensitive
+    public ClassLoader getClassLoader() {
+        ClassLoader cl = getClassLoader0();
+        if (cl == null)
+            return null;
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            ClassLoader.checkClassLoaderPermission(cl, Reflection.getCallerClass());
+        }
+        return cl;
+    }
+

扩展类加载器

这个类加载器是在类sun.misc.Launcher.ExtClassLoader中以 Java 代码的形式实现的,它负责在家\lib\ext 目录中,或者被 java.ext.dirs系统变量中所指定的路径中的所有类库,它其实目的是为了实现 Java 系统类库的扩展机制

+

应用程序类加载器

这个类加载器是由sun.misc.Launcher.AppClassLoader实现,通过 java 代码,并且是 ClassLoader 类中的 getSystemClassLoader()方法的返回值,可以看一下代码

+
/**
+     * Returns the system class loader for delegation.  This is the default
+     * delegation parent for new <tt>ClassLoader</tt> instances, and is
+     * typically the class loader used to start the application.
+     *
+     * <p> This method is first invoked early in the runtime's startup
+     * sequence, at which point it creates the system class loader and sets it
+     * as the context class loader of the invoking <tt>Thread</tt>.
+     *
+     * <p> The default system class loader is an implementation-dependent
+     * instance of this class.
+     *
+     * <p> If the system property "<tt>java.system.class.loader</tt>" is defined
+     * when this method is first invoked then the value of that property is
+     * taken to be the name of a class that will be returned as the system
+     * class loader.  The class is loaded using the default system class loader
+     * and must define a public constructor that takes a single parameter of
+     * type <tt>ClassLoader</tt> which is used as the delegation parent.  An
+     * instance is then created using this constructor with the default system
+     * class loader as the parameter.  The resulting class loader is defined
+     * to be the system class loader.
+     *
+     * <p> If a security manager is present, and the invoker's class loader is
+     * not <tt>null</tt> and the invoker's class loader is not the same as or
+     * an ancestor of the system class loader, then this method invokes the
+     * security manager's {@link
+     * SecurityManager#checkPermission(java.security.Permission)
+     * <tt>checkPermission</tt>} method with a {@link
+     * RuntimePermission#RuntimePermission(String)
+     * <tt>RuntimePermission("getClassLoader")</tt>} permission to verify
+     * access to the system class loader.  If not, a
+     * <tt>SecurityException</tt> will be thrown.  </p>
+     *
+     * @return  The system <tt>ClassLoader</tt> for delegation, or
+     *          <tt>null</tt> if none
+     *
+     * @throws  SecurityException
+     *          If a security manager exists and its <tt>checkPermission</tt>
+     *          method doesn't allow access to the system class loader.
+     *
+     * @throws  IllegalStateException
+     *          If invoked recursively during the construction of the class
+     *          loader specified by the "<tt>java.system.class.loader</tt>"
+     *          property.
+     *
+     * @throws  Error
+     *          If the system property "<tt>java.system.class.loader</tt>"
+     *          is defined but the named class could not be loaded, the
+     *          provider class does not define the required constructor, or an
+     *          exception is thrown by that constructor when it is invoked. The
+     *          underlying cause of the error can be retrieved via the
+     *          {@link Throwable#getCause()} method.
+     *
+     * @revised  1.4
+     */
+    @CallerSensitive
+    public static ClassLoader getSystemClassLoader() {
+        initSystemClassLoader();
+        if (scl == null) {
+            return null;
+        }
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            checkClassLoaderPermission(scl, Reflection.getCallerClass());
+        }
+        return scl;
+    }
+    private static synchronized void initSystemClassLoader() {
+        if (!sclSet) {
+            if (scl != null)
+                throw new IllegalStateException("recursive invocation");
+            // 主要的第一步是这
+            sun.misc.Launcher l = sun.misc.Launcher.getLauncher();
+            if (l != null) {
+                Throwable oops = null;
+                // 然后是这
+                scl = l.getClassLoader();
+                try {
+                    scl = AccessController.doPrivileged(
+                        new SystemClassLoaderAction(scl));
+                } catch (PrivilegedActionException pae) {
+                    oops = pae.getCause();
+                    if (oops instanceof InvocationTargetException) {
+                        oops = oops.getCause();
+                    }
+                }
+                if (oops != null) {
+                    if (oops instanceof Error) {
+                        throw (Error) oops;
+                    } else {
+                        // wrap the exception
+                        throw new Error(oops);
+                    }
+                }
+            }
+            sclSet = true;
+        }
+    }
+// 接着跟到sun.misc.Launcher#getClassLoader
+public ClassLoader getClassLoader() {
+        return this.loader;
+    }
+// 然后看到这 sun.misc.Launcher#Launcher
+public Launcher() {
+        Launcher.ExtClassLoader var1;
+        try {
+            var1 = Launcher.ExtClassLoader.getExtClassLoader();
+        } catch (IOException var10) {
+            throw new InternalError("Could not create extension class loader", var10);
+        }
 
-"GC task thread#3 (ParallelGC)" os_prio=31 tid=0x00007fc9df002800 nid=0x5203 runnable 
+        try {
+            // 可以看到 就是 AppClassLoader
+            this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);
+        } catch (IOException var9) {
+            throw new InternalError("Could not create application class loader", var9);
+        }
 
-"VM Periodic Task Thread" os_prio=31 tid=0x00007fc9df11a800 nid=0x3a03 waiting on condition 
+        Thread.currentThread().setContextClassLoader(this.loader);
+        String var2 = System.getProperty("java.security.manager");
+        if (var2 != null) {
+            SecurityManager var3 = null;
+            if (!"".equals(var2) && !"default".equals(var2)) {
+                try {
+                    var3 = (SecurityManager)this.loader.loadClass(var2).newInstance();
+                } catch (IllegalAccessException var5) {
+                } catch (InstantiationException var6) {
+                } catch (ClassNotFoundException var7) {
+                } catch (ClassCastException var8) {
+                }
+            } else {
+                var3 = new SecurityManager();
+            }
 
-JNI global references: 1087
+            if (var3 == null) {
+                throw new InternalError("Could not create SecurityManager: " + var2);
+            }
 
+            System.setSecurityManager(var3);
+        }
 
-Found one Java-level deadlock:
-=============================
-"mythread2":
-  waiting for ownable synchronizer 0x000000076f5d4330, (a java.util.concurrent.locks.ReentrantLock$NonfairSync),
-  which is held by "mythread1"
-"mythread1":
-  waiting for ownable synchronizer 0x000000076f5d4360, (a java.util.concurrent.locks.ReentrantLock$NonfairSync),
-  which is held by "mythread2"
+    }
+

它负责加载用户类路径(ClassPath)上所有的类库,我们可以直接在代码中使用这个类加载器,如果我们的代码中没有自定义的类在加载器,一般情况下这个就是程序中默认的类加载器

+

双亲委派模型


双亲委派模型的工作过程是:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试家在这个类,而是把这个请求为派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的家在请求最终都应该传送到最顶层的启动类加载器中,只有当父类加载器反馈自己无法完成加载请求(它的搜索范围中没有找到所需要的类)时,子加载器才会尝试自己去完成加载。
使用双亲委派模型来组织类加载器之间的关系,一个显而易见的好处就是 Java 中的类随着它的类加载器一起举杯了一种带有优先级的层次关系。例如类 java.lang.Object,它存放在 rt.jar 之中,无论哪一个类加载器要家在这个类,最终都是委派给处于模型最顶层的启动类加载器进行加载,因此 Object 类在程序的各种类加载器环境中都能够保证是同一个类。反之,如果没有使用双薪委派模型,都由各个类加载器自行去加载的话,如果用户自己也编写了一个名为 java.lang.Object 的类,并放在程序的 ClassPath 中,那系统中就会出现多个不同的 Object 类,Java 类型体系中最基础的行为也就无从保证,应用程序将会变得一片混乱。
可以来看下双亲委派模型的代码实现

+
/**
+     * Loads the class with the specified <a href="#name">binary name</a>.  The
+     * default implementation of this method searches for classes in the
+     * following order:
+     *
+     * <ol>
+     *
+     *   <li><p> Invoke {@link #findLoadedClass(String)} to check if the class
+     *   has already been loaded.  </p></li>
+     *
+     *   <li><p> Invoke the {@link #loadClass(String) <tt>loadClass</tt>} method
+     *   on the parent class loader.  If the parent is <tt>null</tt> the class
+     *   loader built-in to the virtual machine is used, instead.  </p></li>
+     *
+     *   <li><p> Invoke the {@link #findClass(String)} method to find the
+     *   class.  </p></li>
+     *
+     * </ol>
+     *
+     * <p> If the class was found using the above steps, and the
+     * <tt>resolve</tt> flag is true, this method will then invoke the {@link
+     * #resolveClass(Class)} method on the resulting <tt>Class</tt> object.
+     *
+     * <p> Subclasses of <tt>ClassLoader</tt> are encouraged to override {@link
+     * #findClass(String)}, rather than this method.  </p>
+     *
+     * <p> Unless overridden, this method synchronizes on the result of
+     * {@link #getClassLoadingLock <tt>getClassLoadingLock</tt>} method
+     * during the entire class loading process.
+     *
+     * @param  name
+     *         The <a href="#name">binary name</a> of the class
+     *
+     * @param  resolve
+     *         If <tt>true</tt> then resolve the class
+     *
+     * @return  The resulting <tt>Class</tt> object
+     *
+     * @throws  ClassNotFoundException
+     *          If the class could not be found
+     */
+    protected Class<?> loadClass(String name, boolean resolve)
+        throws ClassNotFoundException
+    {
+        synchronized (getClassLoadingLock(name)) {
+            // First, check if the class has already been loaded
+            Class<?> c = findLoadedClass(name);
+            if (c == null) {
+                long t0 = System.nanoTime();
+                try {
+                    if (parent != null) {
+                        // 委托父类加载
+                        c = parent.loadClass(name, false);
+                    } else {
+                        // 使用启动类加载器
+                        c = findBootstrapClassOrNull(name);
+                    }
+                } catch (ClassNotFoundException e) {
+                    // ClassNotFoundException thrown if class not found
+                    // from the non-null parent class loader
+                }
 
-Java stack information for the threads listed above:
-===================================================
-"mythread2":
-        at sun.misc.Unsafe.park(Native Method)
-        - parking to wait for  <0x000000076f5d4330> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
-        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
-        at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
-        at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)
-        at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)
-        at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)
-        at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)
-        at com.nicksxs.thread_dump_demo.ThreadDumpDemoApplication$2.run(ThreadDumpDemoApplication.java:34)
-"mythread1":
-        at sun.misc.Unsafe.park(Native Method)
-        - parking to wait for  <0x000000076f5d4360> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
-        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
-        at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
-        at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)
-        at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)
-        at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)
-        at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)
-        at com.nicksxs.thread_dump_demo.ThreadDumpDemoApplication$1.run(ThreadDumpDemoApplication.java:22)
+                if (c == null) {
+                    // If still not found, then invoke findClass in order
+                    // to find the class.
+                    long t1 = System.nanoTime();
+                    // 调用自己的 findClass() 方法尝试进行加载
+                    c = findClass(name);
 
-Found 1 deadlock.
-

前面的信息其实上次就看过了,后面就可以发现有个死锁了,

上面比较长,把主要的截出来,就是这边的,这点就很强大了。

-

jmap

惯例还是看一下帮助信息

这个相对命令比较多,不过因为现在 dump 下来我们可能会用文件模式,然后将文件下载下来使用 mat 进行分析,所以可以使用
jmap -dump:live,format=b,file=heap.bin <pid>
命令照着上面看的就是打印活着的对象,然后以二进制格式,文件名叫 heap.bin 然后最后就是进程 id,打印出来以后可以用 mat 打开

这样就可以很清晰的看到应用里的各种信息,jmap 直接在命令中还可以看很多信息,比如使用jmap -histo <pid>打印对象的实例数和对象占用的内存

jmap -finalizerinfo <pid> 打印正在等候回收的对象

-

小tips

对于一些应用内存已经占满了,jstack 和 jmap 可能会连不上的情况,可以使用-F参数强制打印线程或者 dump 文件,但是要注意这两者使用的用户必须与 java 进程启动用户一致,并且使用的 jdk 也要一致

+ // this is the defining class loader; record the stats + sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); + sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); + sun.misc.PerfCounter.getFindClasses().increment(); + } + } + if (resolve) { + resolveClass(c); + } + return c; + } + }
+

破坏双亲委派

关于破坏双亲委派模型,第一次是在 JDK1.2 之后引入了双亲委派模型之前,那么在那之前已经有了类加载器,所以java.lang.ClassLoader 中添加了一个 protected 方法 findClass(),并引导用户编写的类加载逻辑时尽可能去重写这个方法,而不是在 loadClass()中编写代码。这个跟上面的逻辑其实类似,当父类加载失败,会调用 findClass()来完成加载;第二次是因为这个模型本身还有一些不足之处,比如 SPI 这种,所以有设计了线程下上下文类加载器(Thread Context ClassLoader)。这个类加载器可以通过 java.lang.Thread 类的 java.lang.Thread#setContextClassLoader() 进行设置,然后第三种是为了追求程序动态性,这里有涉及到了 osgi 等概念,就不展开了

]]> Java - Thread dump - 问题排查 - 工具 Java - JPS - JStack - JMap + 类加载 + 加载 + 验证 + 准备 + 解析 + 初始化 + 链接 + 双亲委派 @@ -16188,9 +16214,9 @@ public Result invoke(final Invocation invocation) throws RpcException { 排序 + 小技巧 排序 linux - 小技巧 top @@ -16719,6 +16745,35 @@ result = result Broker + + 聊聊 Sharding-Jdbc 的简单原理初篇 + /2021/12/26/%E8%81%8A%E8%81%8A-Sharding-Jdbc-%E7%9A%84%E7%AE%80%E5%8D%95%E5%8E%9F%E7%90%86%E5%88%9D%E7%AF%87/ + 在上一篇 sharding-jdbc 的介绍中其实碰到过一个问题,这里也引出了一个比较有意思的话题
就是我在执行 query 的时候犯过一个比较难发现的错误,

+
ResultSet resultSet = ps.executeQuery(sql);
+

实际上应该是

+
ResultSet resultSet = ps.executeQuery();
+

而这里的差别就是,是否传 sql 这个参数,首先我们要知道这个 ps 是什么,它也是个接口java.sql.PreparedStatement,而真正的实现类是org.apache.shardingsphere.driver.jdbc.core.statement.ShardingSpherePreparedStatement,我们来看下继承关系

这里可以看到继承关系里有org.apache.shardingsphere.driver.jdbc.unsupported.AbstractUnsupportedOperationPreparedStatement
那么在我上面的写错的代码里

+
@Override
+public final ResultSet executeQuery(final String sql) throws SQLException {
+    throw new SQLFeatureNotSupportedException("executeQuery with SQL for PreparedStatement");
+}
+

这个报错一开始让我有点懵,后来点进去了发现是这么个异常,但是我其实一开始是用的更新语句,以为更新不支持,因为平时使用没有深究过,以为是不是需要使用 Mybatis 才可以执行更新,但是理论上也不应该,再往上看原来这些异常是由 sharding-jdbc 包装的,也就是在上面说的AbstractUnsupportedOperationPreparedStatement,这其实也是一种设计思想,本身 jdbc 提供了一系列接口,由各家去支持,包括 mysql,sql server,oracle 等,而正因为这个设计,所以 sharding-jdbc 也可以在此基础上进行设计,我们可以总体地看下 sharding-jdbc 的实现基础

看了前面ShardingSpherePreparedStatement的继承关系,应该也能猜到这里的几个类都是实现了 jdbc 的基础接口,

在前一篇的 demo 中的

+
Connection conn = dataSource.getConnection();
+

其实就获得了org.apache.shardingsphere.driver.jdbc.core.connection.ShardingSphereConnection#ShardingSphereConnection
然后获得java.sql.PreparedStatement

+
PreparedStatement ps = conn.prepareStatement(sql)
+

就是获取了org.apache.shardingsphere.driver.jdbc.core.statement.ShardingSpherePreparedStatement
然后就是执行

+
ResultSet resultSet = ps.executeQuery();
+

然后获得结果
org.apache.shardingsphere.driver.jdbc.core.resultset.ShardingSphereResultSet

+

其实像 mybatis 也是基于这样去实现的

+]]>
+ + Java + + + Java + Sharding-Jdbc + +
聊聊 Sharding-Jdbc 分库分表下的分页方案 /2022/01/09/%E8%81%8A%E8%81%8A-Sharding-Jdbc-%E5%88%86%E5%BA%93%E5%88%86%E8%A1%A8%E4%B8%8B%E7%9A%84%E5%88%86%E9%A1%B5%E6%96%B9%E6%A1%88/ @@ -16905,35 +16960,6 @@ t2 } }

看下查询结果

-]]> - - Java - - - Java - Sharding-Jdbc - - - - 聊聊 Sharding-Jdbc 的简单原理初篇 - /2021/12/26/%E8%81%8A%E8%81%8A-Sharding-Jdbc-%E7%9A%84%E7%AE%80%E5%8D%95%E5%8E%9F%E7%90%86%E5%88%9D%E7%AF%87/ - 在上一篇 sharding-jdbc 的介绍中其实碰到过一个问题,这里也引出了一个比较有意思的话题
就是我在执行 query 的时候犯过一个比较难发现的错误,

-
ResultSet resultSet = ps.executeQuery(sql);
-

实际上应该是

-
ResultSet resultSet = ps.executeQuery();
-

而这里的差别就是,是否传 sql 这个参数,首先我们要知道这个 ps 是什么,它也是个接口java.sql.PreparedStatement,而真正的实现类是org.apache.shardingsphere.driver.jdbc.core.statement.ShardingSpherePreparedStatement,我们来看下继承关系

这里可以看到继承关系里有org.apache.shardingsphere.driver.jdbc.unsupported.AbstractUnsupportedOperationPreparedStatement
那么在我上面的写错的代码里

-
@Override
-public final ResultSet executeQuery(final String sql) throws SQLException {
-    throw new SQLFeatureNotSupportedException("executeQuery with SQL for PreparedStatement");
-}
-

这个报错一开始让我有点懵,后来点进去了发现是这么个异常,但是我其实一开始是用的更新语句,以为更新不支持,因为平时使用没有深究过,以为是不是需要使用 Mybatis 才可以执行更新,但是理论上也不应该,再往上看原来这些异常是由 sharding-jdbc 包装的,也就是在上面说的AbstractUnsupportedOperationPreparedStatement,这其实也是一种设计思想,本身 jdbc 提供了一系列接口,由各家去支持,包括 mysql,sql server,oracle 等,而正因为这个设计,所以 sharding-jdbc 也可以在此基础上进行设计,我们可以总体地看下 sharding-jdbc 的实现基础

看了前面ShardingSpherePreparedStatement的继承关系,应该也能猜到这里的几个类都是实现了 jdbc 的基础接口,

在前一篇的 demo 中的

-
Connection conn = dataSource.getConnection();
-

其实就获得了org.apache.shardingsphere.driver.jdbc.core.connection.ShardingSphereConnection#ShardingSphereConnection
然后获得java.sql.PreparedStatement

-
PreparedStatement ps = conn.prepareStatement(sql)
-

就是获取了org.apache.shardingsphere.driver.jdbc.core.statement.ShardingSpherePreparedStatement
然后就是执行

-
ResultSet resultSet = ps.executeQuery();
-

然后获得结果
org.apache.shardingsphere.driver.jdbc.core.resultset.ShardingSphereResultSet

-

其实像 mybatis 也是基于这样去实现的

]]>
Java @@ -17001,120 +17027,7 @@ t2 FixedThreadPool LimitedThreadPool EagerThreadPool - CachedThreadPool - -
- - 聊聊 mysql 的 MVCC 续篇 - /2020/05/02/%E8%81%8A%E8%81%8A-mysql-%E7%9A%84-MVCC-%E7%BB%AD%E7%AF%87/ - 上一篇聊了mysql 的 innodb 引擎基于 read view 实现的 mvcc 和事务隔离级别,可能有些细心的小伙伴会发现一些问题,第一个是在 RC 级别下的事务提交后的可见性,这里涉及到了三个参数,m_low_limit_id,m_up_limit_id,m_ids,之前看到知乎的一篇写的非常不错的文章,但是就在这一点上似乎有点疑惑,这里基于源码和注释来解释下这个问题

-
/**
-Opens a read view where exactly the transactions serialized before this
-point in time are seen in the view.
-@param id		Creator transaction id */
-
-void ReadView::prepare(trx_id_t id) {
-  ut_ad(mutex_own(&trx_sys->mutex));
-
-  m_creator_trx_id = id;
-
-  m_low_limit_no = m_low_limit_id = m_up_limit_id = trx_sys->max_trx_id;
-

m_low_limit_id赋的值是trx_sys->max_trx_id,代表的是当前系统最小的未分配的事务 id,所以呢,举个例子,当前有三个活跃事务,事务 id 分别是 100,200,300,而 m_up_limit_id = 100, m_low_limit_id = 301,当事务 id 是 200 的提交之后,它的更新就是可以被 100 和 300 看到,而不是说 m_ids 里没了 200,并且 200 比 100 大就应该不可见了

-

幻读

还有一个问题是幻读的问题,这貌似也是个高频面试题,啥意思呢,或者说跟它最常拿来比较的脏读,脏读是指读到了别的事务未提交的数据,因为未提交,严格意义上来讲,不一定是会被最后落到库里,可能会回滚,也就是在 read uncommitted 级别下会出现的问题,但是幻读不太一样,幻读是指两次查询的结果数量不一样,比如我查了第一次是 select * from table1 where id < 10 for update,查出来了一条结果 id 是 5,然后再查一下发现出来了一条 id 是 5,一条 id 是 7,那是不是有点尴尬了,其实呢这个点我觉得脏读跟幻读也比较是从原理层面来命名,如果第一次接触的同学发觉有点不理解也比较正常,因为从逻辑上讲总之都是数据不符合预期,但是基于源码层面其实是不同的情况,幻读是在原先的 read view 无法完全解决的,怎么解决呢,简单的来说就是锁咯,我们知道innodb 是基于 record lock 行锁的,但是貌似没有办法解决这种问题,那么 innodb 就引入了 gap lock 间隙锁,比如上面说的情况下,id 小于 10 的情况下,是都应该锁住的,gap lock 其实是基于索引结构来锁的,因为索引树除了树形结构之外,还有一个next record 的指针,gap lock 也是基于这个来锁的
看一下 mysql 的文档

-
-

SELECT … FOR UPDATE sets an exclusive next-key lock on every record the search encounters. However, only an index record lock is required for statements that lock rows using a unique index to search for a unique row.

-
-

对于一个 for update 查询,在 RR 级别下,会设置一个 next-key lock在每一条被查询到的记录上,next-lock 又是啥呢,其实就是 gap 锁和 record 锁的结合体,比如我在数据库里有 id 是 1,3,5,7,10,对于上面那条查询,查出来的结果就是 1,3,5,7,那么按照文档里描述的,对于这几条记录都会加上next-key lock,也就是(-∞, 1], (1, 3], (3, 5], (5, 7], (7, 10) 这些区间和记录会被锁起来,不让插入,再唠叨一下呢,就是其实如果是只读的事务,光 read view 一致性读就够了,如果是有写操作的呢,就需要锁了。

-]]>
- - Mysql - C - 数据结构 - 源码 - Mysql - - - mysql - 数据结构 - 源码 - mvcc - read view - gap lock - next-key lock - 幻读 - -
- - 聊聊 Java 的类加载机制一 - /2020/11/08/%E8%81%8A%E8%81%8A-Java-%E7%9A%84%E7%B1%BB%E5%8A%A0%E8%BD%BD%E6%9C%BA%E5%88%B6/ - 一说到这个主题,想到的应该是双亲委派模型,不过讲的包括但不限于这个,主要内容是参考深入理解 Java 虚拟机书中的介绍,
一个类型的生命周期包含了七个阶段,加载,验证,准备,解析,初始化,使用,卸载。

-
    -
  • 加载

  • -
-
    -
  1. 通过一个类的全限定名来获取定义此类的二进制字节流
  2. -
  3. 将这个字节流代表的静态存储结构转化为方法区的运行时数据结构
  4. -
  5. 在内存中生成了一个代表这个类的 java.lang.Class 对象,作为方法区这个类的各种数据的访问入口
  6. -
-
    -
  • 验证

  • -
-
    -
  1. 文件格式验证
  2. -
  3. 元数据验证
  4. -
  5. 字节码验证
  6. -
  7. 符号引用验证
  8. -
-
    -
  • 准备

    准备阶段是正式为类中定义的变量(即静态变量,被static修饰的变量)分配内存并设置类变量初始值的阶段

    -
  • -
  • 解析

    解析阶段是 Java 虚拟机将常量池内的符号引用替换为直接引用的过程

    -
  • -
-

以上验证准备解析 三个阶段又合称为链接阶段,链接阶段要做的是将加载到JVM中的二进制字节流的类数据信息合并到JVM的运行时状态中。

-
    -
  • 初始化

    类的初始化阶段是类加载过程的最后一个步骤,也是除了自定义类加载器之外将主动权交给了应用程序,其实就是执行类构造器()方法的过程,()并不是我们在 Java 代码中直接编写的方法,它是 Javac编译器的自动生成物,()方法是由编译器自动收集类中的所有类变量的复制动作和静态句块(static{}块)中的语句合并产生的,编译器收集的顺序是由语句在原文件中出现的顺序决定的,静态语句块中只能访问定义在静态语句块之前的变量,定义在它之后的变量,在前面的静态语句块可以复制,但是不能访问,同时还要保证父类的执行先于子类,然后保证多线程下的并发问题
  • -
-

最终,方法区会存储当前类类信息,包括类的静态变量、类初始化代码(定义静态变量时的赋值语句 和 静态初始化代码块)、实例变量定义、实例初始化代码(定义实例变量时的赋值语句实例代码块和构造方法)和实例方法,还有父类的类信息引用。

-]]>
- - Java - 类加载 - -
- - 聊聊 mysql 的 MVCC 续续篇之锁分析 - /2020/05/10/%E8%81%8A%E8%81%8A-mysql-%E7%9A%84-MVCC-%E7%BB%AD%E7%BB%AD%E7%AF%87%E4%B9%8B%E5%8A%A0%E9%94%81%E5%88%86%E6%9E%90/ - 看完前面两篇水文之后,感觉不得不来分析下 mysql 的锁了,其实前面说到幻读的时候是有个前提没提到的,比如一个select * from table1 where id = 1这种查询语句其实是不会加传说中的锁的,当然这里是指在 RR 或者 RC 隔离级别下,
看一段 mysql官方文档

-
-

SELECT ... FROM is a consistent read, reading a snapshot of the database and setting no locks unless the transaction isolation level is set to SERIALIZABLE. For SERIALIZABLE level, the search sets shared next-key locks on the index records it encounters. However, only an index record lock is required for statements that lock rows using a unique index to search for a unique row.

-
-

纯粹的这种一致性读,实际读取的是快照,也就是基于 read view 的读取方式,除非当前隔离级别是SERIALIZABLE
但是对于以下几类

-
    -
  • select * from table where ? lock in share mode;
  • -
  • select * from table where ? for update;
  • -
  • insert into table values (...);
  • -
  • update table set ? where ?;
  • -
  • delete from table where ?;
  • -
-

除了第一条是 S 锁之外,其他都是 X 排他锁,这边在顺带下,S 锁表示共享锁, X 表示独占锁,同为 S 锁之间不冲突,S 与 X,X 与 S,X 与 X 之间都冲突,也就是加了前者,后者就加不上了
我们知道对于 RC 级别会出现幻读现象,对于 RR 级别不会出现,主要的区别是 RR 级别下对于以上的加锁读取都根据情况加上了 gap 锁,那么是不是 RR 级别下以上所有的都是要加 gap 锁呢,当然不是
举个例子,RR 事务隔离级别下,table1 有个主键id 字段
select * from table1 where id = 10 for update
这条语句要加 gap 锁吗?
答案是不需要,这里其实算是我看了这么久的一点自己的理解,啥时候要加 gap 锁,判断的条件是根据我查询的数据是否会因为不加 gap 锁而出现数量的不一致,我上面这条查询语句,在什么情况下会出现查询结果数量不一致呢,只要在这条记录被更新或者删除的时候,有没有可能我第一次查出来一条,第二次变成两条了呢,不可能,因为是主键索引。
再变更下这个题的条件,当 id 不是主键,但是是唯一索引,这样需要怎么加锁,注意问题是怎么加锁,不是需不需要加 gap 锁,这里呢就是稍微延伸一下,把聚簇索引(主键索引)和二级索引带一下,当 id 不是主键,说明是个二级索引,但是它是唯一索引,体会下,首先对于 id = 10这个二级索引肯定要加锁,要不要锁 gap 呢,不用,因为是唯一索引,id = 10 只可能有这一条记录,然后呢,这样是不是就好了,还不行,因为啥,因为它是二级索引,对应的主键索引的记录才是真正的数据,万一被更新掉了咋办,所以在 id = 10 对应的主键索引上也需要加上锁(默认都是 record lock行锁),那主键索引上要不要加 gap 呢,也不用,也是精确定位到这一条记录
最后呢,当 id 不是主键,也不是唯一索引,只是个普通的索引,这里就需要大名鼎鼎的 gap 锁了,
是时候画个图了

其实核心的目的还是不让这个 id=10 的记录不会出现幻读,那么就需要在 id 这个索引上加上三个 gap 锁,主键索引上就不用了,在 id 索引上已经控制住了id = 10 不会出现幻读,主键索引上这两条对应的记录已经锁了,所以就这样 OK 了

-]]>
- - Mysql - C - 数据结构 - 源码 - Mysql - - - mysql - 数据结构 - 源码 - mvcc - read view - gap lock - next-key lock - 幻读 + CachedThreadPool
@@ -17197,6 +17110,81 @@ constexpr size_t DATA_ROLL_PTR_LEN read view + + 聊聊 mysql 的 MVCC 续续篇之锁分析 + /2020/05/10/%E8%81%8A%E8%81%8A-mysql-%E7%9A%84-MVCC-%E7%BB%AD%E7%BB%AD%E7%AF%87%E4%B9%8B%E5%8A%A0%E9%94%81%E5%88%86%E6%9E%90/ + 看完前面两篇水文之后,感觉不得不来分析下 mysql 的锁了,其实前面说到幻读的时候是有个前提没提到的,比如一个select * from table1 where id = 1这种查询语句其实是不会加传说中的锁的,当然这里是指在 RR 或者 RC 隔离级别下,
看一段 mysql官方文档

+
+

SELECT ... FROM is a consistent read, reading a snapshot of the database and setting no locks unless the transaction isolation level is set to SERIALIZABLE. For SERIALIZABLE level, the search sets shared next-key locks on the index records it encounters. However, only an index record lock is required for statements that lock rows using a unique index to search for a unique row.

+
+

纯粹的这种一致性读,实际读取的是快照,也就是基于 read view 的读取方式,除非当前隔离级别是SERIALIZABLE
但是对于以下几类

+
    +
  • select * from table where ? lock in share mode;
  • +
  • select * from table where ? for update;
  • +
  • insert into table values (...);
  • +
  • update table set ? where ?;
  • +
  • delete from table where ?;
  • +
+

除了第一条是 S 锁之外,其他都是 X 排他锁,这边在顺带下,S 锁表示共享锁, X 表示独占锁,同为 S 锁之间不冲突,S 与 X,X 与 S,X 与 X 之间都冲突,也就是加了前者,后者就加不上了
我们知道对于 RC 级别会出现幻读现象,对于 RR 级别不会出现,主要的区别是 RR 级别下对于以上的加锁读取都根据情况加上了 gap 锁,那么是不是 RR 级别下以上所有的都是要加 gap 锁呢,当然不是
举个例子,RR 事务隔离级别下,table1 有个主键id 字段
select * from table1 where id = 10 for update
这条语句要加 gap 锁吗?
答案是不需要,这里其实算是我看了这么久的一点自己的理解,啥时候要加 gap 锁,判断的条件是根据我查询的数据是否会因为不加 gap 锁而出现数量的不一致,我上面这条查询语句,在什么情况下会出现查询结果数量不一致呢,只要在这条记录被更新或者删除的时候,有没有可能我第一次查出来一条,第二次变成两条了呢,不可能,因为是主键索引。
再变更下这个题的条件,当 id 不是主键,但是是唯一索引,这样需要怎么加锁,注意问题是怎么加锁,不是需不需要加 gap 锁,这里呢就是稍微延伸一下,把聚簇索引(主键索引)和二级索引带一下,当 id 不是主键,说明是个二级索引,但是它是唯一索引,体会下,首先对于 id = 10这个二级索引肯定要加锁,要不要锁 gap 呢,不用,因为是唯一索引,id = 10 只可能有这一条记录,然后呢,这样是不是就好了,还不行,因为啥,因为它是二级索引,对应的主键索引的记录才是真正的数据,万一被更新掉了咋办,所以在 id = 10 对应的主键索引上也需要加上锁(默认都是 record lock行锁),那主键索引上要不要加 gap 呢,也不用,也是精确定位到这一条记录
最后呢,当 id 不是主键,也不是唯一索引,只是个普通的索引,这里就需要大名鼎鼎的 gap 锁了,
是时候画个图了

其实核心的目的还是不让这个 id=10 的记录不会出现幻读,那么就需要在 id 这个索引上加上三个 gap 锁,主键索引上就不用了,在 id 索引上已经控制住了id = 10 不会出现幻读,主键索引上这两条对应的记录已经锁了,所以就这样 OK 了

+]]>
+ + Mysql + C + 数据结构 + 源码 + Mysql + + + mysql + 数据结构 + 源码 + mvcc + read view + gap lock + next-key lock + 幻读 + +
+ + 聊聊 mysql 的 MVCC 续篇 + /2020/05/02/%E8%81%8A%E8%81%8A-mysql-%E7%9A%84-MVCC-%E7%BB%AD%E7%AF%87/ + 上一篇聊了mysql 的 innodb 引擎基于 read view 实现的 mvcc 和事务隔离级别,可能有些细心的小伙伴会发现一些问题,第一个是在 RC 级别下的事务提交后的可见性,这里涉及到了三个参数,m_low_limit_id,m_up_limit_id,m_ids,之前看到知乎的一篇写的非常不错的文章,但是就在这一点上似乎有点疑惑,这里基于源码和注释来解释下这个问题

+
/**
+Opens a read view where exactly the transactions serialized before this
+point in time are seen in the view.
+@param id		Creator transaction id */
+
+void ReadView::prepare(trx_id_t id) {
+  ut_ad(mutex_own(&trx_sys->mutex));
+
+  m_creator_trx_id = id;
+
+  m_low_limit_no = m_low_limit_id = m_up_limit_id = trx_sys->max_trx_id;
+

m_low_limit_id赋的值是trx_sys->max_trx_id,代表的是当前系统最小的未分配的事务 id,所以呢,举个例子,当前有三个活跃事务,事务 id 分别是 100,200,300,而 m_up_limit_id = 100, m_low_limit_id = 301,当事务 id 是 200 的提交之后,它的更新就是可以被 100 和 300 看到,而不是说 m_ids 里没了 200,并且 200 比 100 大就应该不可见了

+

幻读

还有一个问题是幻读的问题,这貌似也是个高频面试题,啥意思呢,或者说跟它最常拿来比较的脏读,脏读是指读到了别的事务未提交的数据,因为未提交,严格意义上来讲,不一定是会被最后落到库里,可能会回滚,也就是在 read uncommitted 级别下会出现的问题,但是幻读不太一样,幻读是指两次查询的结果数量不一样,比如我查了第一次是 select * from table1 where id < 10 for update,查出来了一条结果 id 是 5,然后再查一下发现出来了一条 id 是 5,一条 id 是 7,那是不是有点尴尬了,其实呢这个点我觉得脏读跟幻读也比较是从原理层面来命名,如果第一次接触的同学发觉有点不理解也比较正常,因为从逻辑上讲总之都是数据不符合预期,但是基于源码层面其实是不同的情况,幻读是在原先的 read view 无法完全解决的,怎么解决呢,简单的来说就是锁咯,我们知道innodb 是基于 record lock 行锁的,但是貌似没有办法解决这种问题,那么 innodb 就引入了 gap lock 间隙锁,比如上面说的情况下,id 小于 10 的情况下,是都应该锁住的,gap lock 其实是基于索引结构来锁的,因为索引树除了树形结构之外,还有一个next record 的指针,gap lock 也是基于这个来锁的
看一下 mysql 的文档

+
+

SELECT … FOR UPDATE sets an exclusive next-key lock on every record the search encounters. However, only an index record lock is required for statements that lock rows using a unique index to search for a unique row.

+
+

对于一个 for update 查询,在 RR 级别下,会设置一个 next-key lock在每一条被查询到的记录上,next-lock 又是啥呢,其实就是 gap 锁和 record 锁的结合体,比如我在数据库里有 id 是 1,3,5,7,10,对于上面那条查询,查出来的结果就是 1,3,5,7,那么按照文档里描述的,对于这几条记录都会加上next-key lock,也就是(-∞, 1], (1, 3], (3, 5], (5, 7], (7, 10) 这些区间和记录会被锁起来,不让插入,再唠叨一下呢,就是其实如果是只读的事务,光 read view 一致性读就够了,如果是有写操作的呢,就需要锁了。

+]]>
+ + Mysql + C + 数据结构 + 源码 + Mysql + + + mysql + 数据结构 + 源码 + mvcc + read view + gap lock + next-key lock + 幻读 + +
聊聊 mysql 索引的一些细节 /2020/12/27/%E8%81%8A%E8%81%8A-mysql-%E7%B4%A2%E5%BC%95%E7%9A%84%E4%B8%80%E4%BA%9B%E7%BB%86%E8%8A%82/ @@ -17318,54 +17306,226 @@ $ // 和饿汉模式相比,这边不需要先实例化出来,注意这里的 volatile,它是必须的 private static volatile Singleton2 instance = null; - private int m = 9; + private int m = 9; + + public static Singleton getInstance() { + if (instance == null) { + // 加锁 + synchronized (Singleton2.class) { + // 这一次判断也是必须的,不然会有并发问题 + if (instance == null) { + instance = new Singleton2(); + } + } + } + return instance; + } +}
+

这里容易错的有三点,理解了其实就比较好记了

+

第一点,为啥不在 getInstance 上整个代码块加 synchronized,这个其实比较容易理解,就是锁的力度太大,性能太差了,这点其实也要去理解,可以举个夸张的例子,比如我一个电商的服务,如果为了避免一个人的订单出现问题,是不是可以从请求入口就把他锁住,到请求结束释放,那么里面做的事情都有保障,然而这显然不可能,因为我们想要这种竞态条件抢占资源的时间尽量减少,防止其他线程等待。
第二点,为啥synchronized之已经检查了 instance == null,还要在里面再检查一次,这个有个术语,叫 double check lock,但是为啥要这么做呢,其实很简单,想象当有两个线程,都过了第一步为空判断,这个时候只有一个线程能拿到这个锁,另一个线程就等待了,如果不再判断一次,那么第一个线程新建完对象释放锁之后,第二个线程又能拿到锁,再去创建一个对象。
第三点,为啥要volatile关键字,原先对它的理解是它修饰的变量在 JMM 中能及时将变量值写到主存中,但是它还有个很重要的作用,就是防止指令重排序,instance = new Singleton();这行代码其实在底层是分成三条指令执行的,第一条是在堆上申请了一块内存放这个对象,但是对象的字段啥的都还是默认值,第二条是设置对象的值,比如上面的 m 是 9,然后第三条是将这个对象和虚拟机栈上的指针建立引用关联,那么如果我不用volatile关键字,这三条指令就有可能出现重排,比如变成了 1-3-2 这种顺序,当执行完第二步时,有个线程来访问这个对象了,先判断是不是空,发现不是空的,就拿去直接用了,是不是就出现问题了,所以这个volatile也是不可缺少的

+

嵌套类

public class Singleton3 {
+
+    private Singleton3() {}
+    // 主要是使用了 嵌套类可以访问外部类的静态属性和静态方法 的特性
+    private static class Holder {
+        private static Singleton3 instance = new Singleton3();
+    }
+    public static Singleton3 getInstance() {
+        return Holder.instance;
+    }
+}
+

这个我个人感觉是饿汉模式的升级版,可以在调用getInstance的时候去实例化对象,也是比较推荐的

+

枚举单例

public enum Singleton {
+    INSTANCE;
+    
+    public void doSomething(){
+        //todo doSomething
+    }
+}
+

枚举很特殊,它在类加载的时候会初始化里面的所有的实例,而且 JVM 保证了它们不会再被实例化,所以它天生就是单例的。

+]]> + + Java + Design Patterns + Singleton + + + 设计模式 + Design Patterns + 单例 + Singleton + + + + 聊聊一次 brew update 引发的血案 + /2020/06/13/%E8%81%8A%E8%81%8A%E4%B8%80%E6%AC%A1-brew-update-%E5%BC%95%E5%8F%91%E7%9A%84%E8%A1%80%E6%A1%88/ + 熟悉我的人(谁熟悉你啊🙄)知道我以前写过 PHP,虽然现在在工作中没用到了,但是自己的一些小工具还是会用 PHP 来写,但是在 Mac 碰到了一个环境相关的问题,因为我也是个更新狂魔,用了 brew 之后因为 gfw 的原因,如果长时间不更新,有时候要装一个用它装一个软件的话,前置的更新耗时就会让人非常头大,所以我基本会隔天 update 一下,但是这样会带来一个很心烦的问题,就是像这样,因为我是要用一个固定版本的 PHP,如果一直升需要一直配扩展啥的也很麻烦,如果一直升级 PHP 到最新版可能会比较少碰到这个问题

+
dyld: Library not loaded: /usr/local/opt/icu4c/lib/libicui18n.64.dylib
+

这是什么鬼啊,然后我去这个目录下看了下,已经都是libicui18n.67.dylib了,而且它没有把原来的版本保留下来,首先这个是个叫 icu4c是啥玩意,谷歌了一下

+
+

ICU4C是ICU在C/C++平台下的版本, ICU(International Component for Unicode)是基于”IBM公共许可证”的,与开源组织合作研究的, 用于支持软件国际化的开源项目。ICU4C提供了C/C++平台强大的国际化开发能力,软件开发者几乎可以使用ICU4C解决任何国际化的问题,根据各地的风俗和语言习惯,实现对数字、货币、时间、日期、和消息的格式化、解析,对字符串进行大小写转换、整理、搜索和排序等功能,必须一提的是,ICU4C提供了强大的BIDI算法,对阿拉伯语等BIDI语言提供了完善的支持。

+
+

然后首先想到的解决方案就是能不能我使用brew install icu4c@64来重装下原来的版本,发现不行,并木有,之前的做法就只能是去网上把 64 的下载下来,然后放到这个目录,比较麻烦不智能,虽然没抱着希望在谷歌着,不过这次竟然给我找到了一个我认为非常 nice 的解决方案,因为是在 Stack Overflow 找到的,本着写给像我这样的小小白看的,那就稍微翻译一下
第一步,我们到 brew的目录下

+
cd $(brew --prefix)/Homebrew/Library/Taps/homebrew/homebrew-core/Formula
+

这个可以理解为是 maven 的 pom 文件,不过有很多不同之处,使用ruby 写的,然后一个文件对应一个组件或者软件,那我们看下有个叫icu4c.rb的文件,
第二步看看它的提交历史

+
git log --follow icu4c.rb
+

在 git log 的海洋中寻找,寻找它的(64版本)的身影

第三步注意这三个红框,Stack Overflow 给出来的答案这一步是找到这个 commit id 直接切出一个新分支

+
git checkout -b icu4c-63 e7f0f10dc63b1dc1061d475f1a61d01b70ef2cb7
+

其实注意 commit id 旁边的红框,这个是有tag 的,可以直接

+
git checkout icu4c-64
+

PS: 因为我的问题是出在 64 的问题,Stack Overflow 回答的是 63 的,反正是一样的解决方法
第四部,切回去之后我们就可以用 brew 提供的基于文件的安装命令来重新装上 64 版本

+
brew reinstall ./icu4c.rb
+

然后就是第五步,切换版本

+
brew switch icu4c 64.2
+

最后把分支切回来

+
git checkout master
+

是不是感觉很厉害的解决方法,大佬还提供了一个更牛的,直接写个 zsh 方法

+
# zsh
+function hiicu64() {
+  local last_dir=$(pwd)
+
+  cd $(brew --prefix)/Homebrew/Library/Taps/homebrew/homebrew-core/Formula
+  git checkout icu4c-4
+  brew reinstall ./icu4c.rb
+  brew switch icu4c 64.2
+  git checkout master
+
+  cd $last_dir
+}
+

对应自己的版本改改版本号就可以了,非常好用。

+]]>
+ + Mac + PHP + Homebrew + PHP + icu4c + + + Mac + PHP + Homebrew + icu4c + zsh + +
+ + 聊聊传说中的 ThreadLocal + /2021/05/30/%E8%81%8A%E8%81%8A%E4%BC%A0%E8%AF%B4%E4%B8%AD%E7%9A%84-ThreadLocal/ + 说来也惭愧,这个 ThreadLocal 其实一直都是一知半解,而且看了一下之后还发现记错了,所以还是记录下
原先记忆里的都是反过来,一个 ThreadLocal 是里面按照 thread 作为 key,存储线程内容的,真的是半解都米有,完全是错的,这样就得用 concurrentHashMap 这种去存储并且要锁定线程了,然后内容也只能存一个了,想想简直智障

+

究竟是啥结构

比如我们在代码中 new 一个 ThreadLocal,

+
public static void main(String[] args) {
+        ThreadLocal<Man> tl = new ThreadLocal<>();
+
+        new Thread(() -> {
+            try {
+                TimeUnit.SECONDS.sleep(2);
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+            System.out.println(tl.get());
+        }).start();
+        new Thread(() -> {
+            try {
+                TimeUnit.SECONDS.sleep(1);
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+            tl.set(new Man());
+        }).start();
+    }
+
+    static class Man {
+        String name = "nick";
+    }
+

这里构造了两个线程,一个先往里设值,一个后从里取,运行看下结果,

知道这个用法的话肯定知道是取不到值的,只是具体的原理原来搞错了,我们来看下设值 set 方法

+
public void set(T value) {
+    Thread t = Thread.currentThread();
+    ThreadLocalMap map = getMap(t);
+    if (map != null)
+        map.set(this, value);
+    else
+        createMap(t, value);
+}
+

写博客这会我才明白我原来咋会错得这么离谱,看到第一行代码 t 就是当前线程,然后第二行就是用这个线程去getMap,然后我是把这个当成从 map 里取值了,其实这里是

+
ThreadLocalMap getMap(Thread t) {
+    return t.threadLocals;
+}
+

获取 t 的 threadLocals 成员变量,那这个 threadLocals 又是啥呢

它其实是线程 Thread 中的一个类型是java.lang.ThreadLocal.ThreadLocalMap的成员变量
这是 ThreadLocal 的一个静态成员变量

+
static class ThreadLocalMap {
+
+        /**
+         * The entries in this hash map extend WeakReference, using
+         * its main ref field as the key (which is always a
+         * ThreadLocal object).  Note that null keys (i.e. entry.get()
+         * == null) mean that the key is no longer referenced, so the
+         * entry can be expunged from table.  Such entries are referred to
+         * as "stale entries" in the code that follows.
+         */
+        static class Entry extends WeakReference<ThreadLocal<?>> {
+            /** The value associated with this ThreadLocal. */
+            Object value;
+
+            Entry(ThreadLocal<?> k, Object v) {
+                super(k);
+                value = v;
+            }
+        }
+    }
+

全部代码有点长,只截取了一小部分,然后我们再回头来分析前面说的 set 过程,再 copy 下代码

+
public void set(T value) {
+    Thread t = Thread.currentThread();
+    ThreadLocalMap map = getMap(t);
+    if (map != null)
+        map.set(this, value);
+    else
+        createMap(t, value);
+}
+

获取到 map 以后呢,如果 map 不为空,就往 map 里 set,这里注意 key 是啥,其实是当前这个 ThreadLocal,这里就比较明白了究竟是啥结构,每个线程都会维护自身的 ThreadLocalMap,它是线程的一个成员变量,当创建 ThreadLocal 的时候,进行设值的时候其实是往这个 map 里以 ThreadLocal 作为 key,往里设 value。

+

内存泄漏是什么鬼

这里又要看下前面的 ThreadLocalMap 结构了,类似 HashMap,它有个 Entry 结构,在设置的时候会先包装成一个 Entry

+
private void set(ThreadLocal<?> key, Object value) {
+
+        // We don't use a fast path as with get() because it is at
+        // least as common to use set() to create new entries as
+        // it is to replace existing ones, in which case, a fast
+        // path would fail more often than not.
+
+        Entry[] tab = table;
+        int len = tab.length;
+        int i = key.threadLocalHashCode & (len-1);
 
-    public static Singleton getInstance() {
-        if (instance == null) {
-            // 加锁
-            synchronized (Singleton2.class) {
-                // 这一次判断也是必须的,不然会有并发问题
-                if (instance == null) {
-                    instance = new Singleton2();
-                }
-            }
-        }
-        return instance;
-    }
-}
-

这里容易错的有三点,理解了其实就比较好记了

-

第一点,为啥不在 getInstance 上整个代码块加 synchronized,这个其实比较容易理解,就是锁的力度太大,性能太差了,这点其实也要去理解,可以举个夸张的例子,比如我一个电商的服务,如果为了避免一个人的订单出现问题,是不是可以从请求入口就把他锁住,到请求结束释放,那么里面做的事情都有保障,然而这显然不可能,因为我们想要这种竞态条件抢占资源的时间尽量减少,防止其他线程等待。
第二点,为啥synchronized之已经检查了 instance == null,还要在里面再检查一次,这个有个术语,叫 double check lock,但是为啥要这么做呢,其实很简单,想象当有两个线程,都过了第一步为空判断,这个时候只有一个线程能拿到这个锁,另一个线程就等待了,如果不再判断一次,那么第一个线程新建完对象释放锁之后,第二个线程又能拿到锁,再去创建一个对象。
第三点,为啥要volatile关键字,原先对它的理解是它修饰的变量在 JMM 中能及时将变量值写到主存中,但是它还有个很重要的作用,就是防止指令重排序,instance = new Singleton();这行代码其实在底层是分成三条指令执行的,第一条是在堆上申请了一块内存放这个对象,但是对象的字段啥的都还是默认值,第二条是设置对象的值,比如上面的 m 是 9,然后第三条是将这个对象和虚拟机栈上的指针建立引用关联,那么如果我不用volatile关键字,这三条指令就有可能出现重排,比如变成了 1-3-2 这种顺序,当执行完第二步时,有个线程来访问这个对象了,先判断是不是空,发现不是空的,就拿去直接用了,是不是就出现问题了,所以这个volatile也是不可缺少的

-

嵌套类

public class Singleton3 {
+        for (Entry e = tab[i];
+             e != null;
+             e = tab[i = nextIndex(i, len)]) {
+            ThreadLocal<?> k = e.get();
 
-    private Singleton3() {}
-    // 主要是使用了 嵌套类可以访问外部类的静态属性和静态方法 的特性
-    private static class Holder {
-        private static Singleton3 instance = new Singleton3();
-    }
-    public static Singleton3 getInstance() {
-        return Holder.instance;
-    }
-}
-

这个我个人感觉是饿汉模式的升级版,可以在调用getInstance的时候去实例化对象,也是比较推荐的

-

枚举单例

public enum Singleton {
-    INSTANCE;
-    
-    public void doSomething(){
-        //todo doSomething
-    }
-}
-

枚举很特殊,它在类加载的时候会初始化里面的所有的实例,而且 JVM 保证了它们不会再被实例化,所以它天生就是单例的。

+ if (k == key) { + e.value = value; + return; + } + + if (k == null) { + replaceStaleEntry(key, value, i); + return; + } + } + + tab[i] = new Entry(key, value); + int sz = ++size; + if (!cleanSomeSlots(i, sz) && sz >= threshold) + rehash(); +}
+

这里其实比较重要的就是前面的 Entry 的构造方法,Entry 是个 WeakReference 的子类,然后在构造方法里可以看到 key 会被包装成一个弱引用,这里为什么使用弱引用,其实是方便这个 key 被回收,如果前面的 ThreadLocal tl实例被设置成 null 了,如果这里是直接的强引用的话,就只能等到线程整个回收了,但是其实是弱引用也会有问题,主要是因为这个 value,如果在 ThreadLocal tl 被设置成 null 了,那么其实这个 value 就会没法被访问到,所以最好的操作还是在使用完了就 remove 掉

]]>
Java - Design Patterns - Singleton - 设计模式 - Design Patterns - 单例 - Singleton + Java + ThreadLocal + 弱引用 + 内存泄漏 + WeakReference
@@ -17673,221 +17833,49 @@ $ org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\ org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\ org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\ -org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\ -org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\ -org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration,\ -org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration,\ -org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration,\ -org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration,\ -org.springframework.boot.autoconfigure.webservices.client.WebServiceTemplateAutoConfiguration - -# Failure analyzers -org.springframework.boot.diagnostics.FailureAnalyzer=\ -org.springframework.boot.autoconfigure.data.redis.RedisUrlSyntaxFailureAnalyzer,\ -org.springframework.boot.autoconfigure.diagnostics.analyzer.NoSuchBeanDefinitionFailureAnalyzer,\ -org.springframework.boot.autoconfigure.flyway.FlywayMigrationScriptMissingFailureAnalyzer,\ -org.springframework.boot.autoconfigure.jdbc.DataSourceBeanCreationFailureAnalyzer,\ -org.springframework.boot.autoconfigure.jdbc.HikariDriverConfigurationFailureAnalyzer,\ -org.springframework.boot.autoconfigure.r2dbc.ConnectionFactoryBeanCreationFailureAnalyzer,\ -org.springframework.boot.autoconfigure.session.NonUniqueSessionRepositoryFailureAnalyzer - -# Template availability providers -org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\ -org.springframework.boot.autoconfigure.freemarker.FreeMarkerTemplateAvailabilityProvider,\ -org.springframework.boot.autoconfigure.mustache.MustacheTemplateAvailabilityProvider,\ -org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAvailabilityProvider,\ -org.springframework.boot.autoconfigure.thymeleaf.ThymeleafTemplateAvailabilityProvider,\ -org.springframework.boot.autoconfigure.web.servlet.JspTemplateAvailabilityProvider - -# DataSource initializer detectors -org.springframework.boot.sql.init.dependency.DatabaseInitializerDetector=\ -org.springframework.boot.autoconfigure.flyway.FlywayMigrationInitializerDatabaseInitializerDetector -
- -

上面根据 org.springframework.boot.autoconfigure.EnableAutoConfiguration 获取的各个配置类,在通过反射加载就能得到一堆 JavaConfig配置类,然后再根据 ConditionalOnProperty等条件配置加载具体的 bean,大致就是这么个逻辑

-]]> - - Java - SpringBoot - - - Java - Spring - SpringBoot - 自动装配 - AutoConfiguration - - - - 聊聊一次 brew update 引发的血案 - /2020/06/13/%E8%81%8A%E8%81%8A%E4%B8%80%E6%AC%A1-brew-update-%E5%BC%95%E5%8F%91%E7%9A%84%E8%A1%80%E6%A1%88/ - 熟悉我的人(谁熟悉你啊🙄)知道我以前写过 PHP,虽然现在在工作中没用到了,但是自己的一些小工具还是会用 PHP 来写,但是在 Mac 碰到了一个环境相关的问题,因为我也是个更新狂魔,用了 brew 之后因为 gfw 的原因,如果长时间不更新,有时候要装一个用它装一个软件的话,前置的更新耗时就会让人非常头大,所以我基本会隔天 update 一下,但是这样会带来一个很心烦的问题,就是像这样,因为我是要用一个固定版本的 PHP,如果一直升需要一直配扩展啥的也很麻烦,如果一直升级 PHP 到最新版可能会比较少碰到这个问题

-
dyld: Library not loaded: /usr/local/opt/icu4c/lib/libicui18n.64.dylib
-

这是什么鬼啊,然后我去这个目录下看了下,已经都是libicui18n.67.dylib了,而且它没有把原来的版本保留下来,首先这个是个叫 icu4c是啥玩意,谷歌了一下

-
-

ICU4C是ICU在C/C++平台下的版本, ICU(International Component for Unicode)是基于”IBM公共许可证”的,与开源组织合作研究的, 用于支持软件国际化的开源项目。ICU4C提供了C/C++平台强大的国际化开发能力,软件开发者几乎可以使用ICU4C解决任何国际化的问题,根据各地的风俗和语言习惯,实现对数字、货币、时间、日期、和消息的格式化、解析,对字符串进行大小写转换、整理、搜索和排序等功能,必须一提的是,ICU4C提供了强大的BIDI算法,对阿拉伯语等BIDI语言提供了完善的支持。

-
-

然后首先想到的解决方案就是能不能我使用brew install icu4c@64来重装下原来的版本,发现不行,并木有,之前的做法就只能是去网上把 64 的下载下来,然后放到这个目录,比较麻烦不智能,虽然没抱着希望在谷歌着,不过这次竟然给我找到了一个我认为非常 nice 的解决方案,因为是在 Stack Overflow 找到的,本着写给像我这样的小小白看的,那就稍微翻译一下
第一步,我们到 brew的目录下

-
cd $(brew --prefix)/Homebrew/Library/Taps/homebrew/homebrew-core/Formula
-

这个可以理解为是 maven 的 pom 文件,不过有很多不同之处,使用ruby 写的,然后一个文件对应一个组件或者软件,那我们看下有个叫icu4c.rb的文件,
第二步看看它的提交历史

-
git log --follow icu4c.rb
-

在 git log 的海洋中寻找,寻找它的(64版本)的身影

第三步注意这三个红框,Stack Overflow 给出来的答案这一步是找到这个 commit id 直接切出一个新分支

-
git checkout -b icu4c-63 e7f0f10dc63b1dc1061d475f1a61d01b70ef2cb7
-

其实注意 commit id 旁边的红框,这个是有tag 的,可以直接

-
git checkout icu4c-64
-

PS: 因为我的问题是出在 64 的问题,Stack Overflow 回答的是 63 的,反正是一样的解决方法
第四部,切回去之后我们就可以用 brew 提供的基于文件的安装命令来重新装上 64 版本

-
brew reinstall ./icu4c.rb
-

然后就是第五步,切换版本

-
brew switch icu4c 64.2
-

最后把分支切回来

-
git checkout master
-

是不是感觉很厉害的解决方法,大佬还提供了一个更牛的,直接写个 zsh 方法

-
# zsh
-function hiicu64() {
-  local last_dir=$(pwd)
-
-  cd $(brew --prefix)/Homebrew/Library/Taps/homebrew/homebrew-core/Formula
-  git checkout icu4c-4
-  brew reinstall ./icu4c.rb
-  brew switch icu4c 64.2
-  git checkout master
-
-  cd $last_dir
-}
-

对应自己的版本改改版本号就可以了,非常好用。

-]]>
- - Mac - PHP - Homebrew - PHP - icu4c - - - Mac - PHP - Homebrew - icu4c - zsh - -
- - 聊聊传说中的 ThreadLocal - /2021/05/30/%E8%81%8A%E8%81%8A%E4%BC%A0%E8%AF%B4%E4%B8%AD%E7%9A%84-ThreadLocal/ - 说来也惭愧,这个 ThreadLocal 其实一直都是一知半解,而且看了一下之后还发现记错了,所以还是记录下
原先记忆里的都是反过来,一个 ThreadLocal 是里面按照 thread 作为 key,存储线程内容的,真的是半解都米有,完全是错的,这样就得用 concurrentHashMap 这种去存储并且要锁定线程了,然后内容也只能存一个了,想想简直智障

-

究竟是啥结构

比如我们在代码中 new 一个 ThreadLocal,

-
public static void main(String[] args) {
-        ThreadLocal<Man> tl = new ThreadLocal<>();
-
-        new Thread(() -> {
-            try {
-                TimeUnit.SECONDS.sleep(2);
-            } catch (InterruptedException e) {
-                e.printStackTrace();
-            }
-            System.out.println(tl.get());
-        }).start();
-        new Thread(() -> {
-            try {
-                TimeUnit.SECONDS.sleep(1);
-            } catch (InterruptedException e) {
-                e.printStackTrace();
-            }
-            tl.set(new Man());
-        }).start();
-    }
-
-    static class Man {
-        String name = "nick";
-    }
-

这里构造了两个线程,一个先往里设值,一个后从里取,运行看下结果,

知道这个用法的话肯定知道是取不到值的,只是具体的原理原来搞错了,我们来看下设值 set 方法

-
public void set(T value) {
-    Thread t = Thread.currentThread();
-    ThreadLocalMap map = getMap(t);
-    if (map != null)
-        map.set(this, value);
-    else
-        createMap(t, value);
-}
-

写博客这会我才明白我原来咋会错得这么离谱,看到第一行代码 t 就是当前线程,然后第二行就是用这个线程去getMap,然后我是把这个当成从 map 里取值了,其实这里是

-
ThreadLocalMap getMap(Thread t) {
-    return t.threadLocals;
-}
-

获取 t 的 threadLocals 成员变量,那这个 threadLocals 又是啥呢

它其实是线程 Thread 中的一个类型是java.lang.ThreadLocal.ThreadLocalMap的成员变量
这是 ThreadLocal 的一个静态成员变量

-
static class ThreadLocalMap {
-
-        /**
-         * The entries in this hash map extend WeakReference, using
-         * its main ref field as the key (which is always a
-         * ThreadLocal object).  Note that null keys (i.e. entry.get()
-         * == null) mean that the key is no longer referenced, so the
-         * entry can be expunged from table.  Such entries are referred to
-         * as "stale entries" in the code that follows.
-         */
-        static class Entry extends WeakReference<ThreadLocal<?>> {
-            /** The value associated with this ThreadLocal. */
-            Object value;
-
-            Entry(ThreadLocal<?> k, Object v) {
-                super(k);
-                value = v;
-            }
-        }
-    }
-

全部代码有点长,只截取了一小部分,然后我们再回头来分析前面说的 set 过程,再 copy 下代码

-
public void set(T value) {
-    Thread t = Thread.currentThread();
-    ThreadLocalMap map = getMap(t);
-    if (map != null)
-        map.set(this, value);
-    else
-        createMap(t, value);
-}
-

获取到 map 以后呢,如果 map 不为空,就往 map 里 set,这里注意 key 是啥,其实是当前这个 ThreadLocal,这里就比较明白了究竟是啥结构,每个线程都会维护自身的 ThreadLocalMap,它是线程的一个成员变量,当创建 ThreadLocal 的时候,进行设值的时候其实是往这个 map 里以 ThreadLocal 作为 key,往里设 value。

-

内存泄漏是什么鬼

这里又要看下前面的 ThreadLocalMap 结构了,类似 HashMap,它有个 Entry 结构,在设置的时候会先包装成一个 Entry

-
private void set(ThreadLocal<?> key, Object value) {
-
-        // We don't use a fast path as with get() because it is at
-        // least as common to use set() to create new entries as
-        // it is to replace existing ones, in which case, a fast
-        // path would fail more often than not.
-
-        Entry[] tab = table;
-        int len = tab.length;
-        int i = key.threadLocalHashCode & (len-1);
+org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\
+org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
+org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration,\
+org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration,\
+org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration,\
+org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration,\
+org.springframework.boot.autoconfigure.webservices.client.WebServiceTemplateAutoConfiguration
 
-        for (Entry e = tab[i];
-             e != null;
-             e = tab[i = nextIndex(i, len)]) {
-            ThreadLocal<?> k = e.get();
+# Failure analyzers
+org.springframework.boot.diagnostics.FailureAnalyzer=\
+org.springframework.boot.autoconfigure.data.redis.RedisUrlSyntaxFailureAnalyzer,\
+org.springframework.boot.autoconfigure.diagnostics.analyzer.NoSuchBeanDefinitionFailureAnalyzer,\
+org.springframework.boot.autoconfigure.flyway.FlywayMigrationScriptMissingFailureAnalyzer,\
+org.springframework.boot.autoconfigure.jdbc.DataSourceBeanCreationFailureAnalyzer,\
+org.springframework.boot.autoconfigure.jdbc.HikariDriverConfigurationFailureAnalyzer,\
+org.springframework.boot.autoconfigure.r2dbc.ConnectionFactoryBeanCreationFailureAnalyzer,\
+org.springframework.boot.autoconfigure.session.NonUniqueSessionRepositoryFailureAnalyzer
 
-            if (k == key) {
-                e.value = value;
-                return;
-            }
+# Template availability providers
+org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\
+org.springframework.boot.autoconfigure.freemarker.FreeMarkerTemplateAvailabilityProvider,\
+org.springframework.boot.autoconfigure.mustache.MustacheTemplateAvailabilityProvider,\
+org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAvailabilityProvider,\
+org.springframework.boot.autoconfigure.thymeleaf.ThymeleafTemplateAvailabilityProvider,\
+org.springframework.boot.autoconfigure.web.servlet.JspTemplateAvailabilityProvider
 
-            if (k == null) {
-                replaceStaleEntry(key, value, i);
-                return;
-            }
-        }
+# DataSource initializer detectors
+org.springframework.boot.sql.init.dependency.DatabaseInitializerDetector=\
+org.springframework.boot.autoconfigure.flyway.FlywayMigrationInitializerDatabaseInitializerDetector
+
- tab[i] = new Entry(key, value); - int sz = ++size; - if (!cleanSomeSlots(i, sz) && sz >= threshold) - rehash(); -}
-

这里其实比较重要的就是前面的 Entry 的构造方法,Entry 是个 WeakReference 的子类,然后在构造方法里可以看到 key 会被包装成一个弱引用,这里为什么使用弱引用,其实是方便这个 key 被回收,如果前面的 ThreadLocal tl实例被设置成 null 了,如果这里是直接的强引用的话,就只能等到线程整个回收了,但是其实是弱引用也会有问题,主要是因为这个 value,如果在 ThreadLocal tl 被设置成 null 了,那么其实这个 value 就会没法被访问到,所以最好的操作还是在使用完了就 remove 掉

+

上面根据 org.springframework.boot.autoconfigure.EnableAutoConfiguration 获取的各个配置类,在通过反射加载就能得到一堆 JavaConfig配置类,然后再根据 ConditionalOnProperty等条件配置加载具体的 bean,大致就是这么个逻辑

]]> Java + SpringBoot Java - ThreadLocal - 弱引用 - 内存泄漏 - WeakReference + Spring + SpringBoot + 自动装配 + AutoConfiguration @@ -17938,27 +17926,28 @@ $ - 聊聊我刚学会的应用诊断方法 - /2020/05/22/%E8%81%8A%E8%81%8A%E6%88%91%E5%88%9A%E5%AD%A6%E4%BC%9A%E7%9A%84%E5%BA%94%E7%94%A8%E8%AF%8A%E6%96%AD%E6%96%B9%E6%B3%95/ - 因为传说中的出身问题,我以前写的是PHP,在使用 swoole 之前,基本的应用调试手段就是简单粗暴的 var_dump,exit,对于单进程模型的 PHP 也是简单有效,技术栈换成 Java 之后,就变得没那么容易,一方面是需要编译,另一方面是一般都是基于 spring 的项目,如果问题定位比较模糊,那框架层的是很难靠简单的 System.out.println 或者打 log 解决,(PS:我觉得可能我写的东西比较适合从 PHP 这种弱类型语言转到 Java 的小白同学)这个时候一方面因为是 Java,有了非常好用的 idea IDE 的支持,可以各种花式调试,条件断点尤其牛叉,但是又因为有 Spring+Java 的双重原因,有些情况下单步调试可以把手按废掉,这也是我之前一直比较困惑苦逼的点,后来随着慢慢精(jiang)进(you)之后,比如对于一个 oom 的情况,我们可以通过启动参数加上-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=xx/xx 来配置溢出时的堆dump 日志,获取到这个文件后,我们可以通过像 Memory Analyzer (MAT)[https://www.eclipse.org/mat/] (The Eclipse Memory Analyzer is a fast and feature-rich Java heap analyzer that helps you find memory leaks and reduce memory consumption.)来查看诊断问题所在,之前用到的时候是因为有个死循环一直往链表里塞数据,属于比较简单的,后来一次是由于运维进行应用迁移时按默认的统一配置了堆内存大小,导致内存的确不够用,所以溢出了,
今天想说的其实主要是我们的 thread dump,这也是我最近才真正用的一个方法,可能真的很小白了,用过 ide 的单步调试其实都知道会有一个一层层的玩意,比如函数从 A,调用了 B,再从 B 调用了 C,一直往下(因为是 Java,所以还有很多🤦‍♂️),这个其实也是大部分语言的调用模型,利用了栈这个数据结构,通过这个结构我们可以知道代码的调用链路,由于对于一个 spring 应用,在本身框架代码量非常庞大的情况下,外加如果应用代码也是非常多的时候,有时候通过单步调试真的很难短时间定位到问题,需要非常大的耐心和仔细观察,当然不是说完全不行,举个例子当我的应用经常启动需要非常长的时间,因为本身应用有非常多个 bean,比较难说究竟是 bean 的加载的确很慢还是有什么异常原因,这种时候就可以使用 thread dump 了,具体怎么操作呢

如果在idea 中运行或者调试时,可以直接点击这个照相机一样的按钮,右边就会出现了左边会显示所有的线程,右边会显示线程栈,

-
"main@1" prio=5 tid=0x1 nid=NA runnable
-  java.lang.Thread.State: RUNNABLE
-	  at TreeDistance.treeDist(TreeDistance.java:64)
-	  at TreeDistance.treeDist(TreeDistance.java:65)
-	  at TreeDistance.treeDist(TreeDistance.java:65)
-	  at TreeDistance.treeDist(TreeDistance.java:65)
-	  at TreeDistance.main(TreeDistance.java:45)
-

这就是我们主线程的堆栈信息了,main 表示这个线程名,prio表示优先级,默认是 5,tid 表示线程 id,nid 表示对应的系统线程,后面的runnable 表示目前线程状态,因为是被我打了断点,所以是就许状态,然后下面就是对应的线程栈内容了,在TreeDistance类的 treeDist方法中,对应的文件行数是 64 行。
这里使用 thread dump一般也不会是上面我截图代码里的这种代码量很少的,一般是大型项目,有时候跑着跑着没反应,又不知道跑到哪了,特别是一些刚接触的大项目或者需要定位一个大项目的一个疑难问题,一时没思路时,可以使用这个方法,个人觉得非常有帮助。

+ 聊一下关于怎么陪伴学习 + /2022/11/06/%E8%81%8A%E4%B8%80%E4%B8%8B%E5%85%B3%E4%BA%8E%E6%80%8E%E4%B9%88%E9%99%AA%E4%BC%B4%E5%AD%A6%E4%B9%A0/ + 这是一次开车过程中结合网上的一些微博想到的,开车是之前LD买了车后,陪领导练车,其实在一开始练车的时候,我们已经是找了相对很空的封闭路段,路上基本很少有车,偶尔有一辆车,但是LD还是很害怕,车速还只有十几的时候,还很远的对面来车的时候就觉得很慌了,这个时候如果以常理肯定会说这样子完全不用怕,如果克服恐惧真的这么容易的话,问题就不会那么纠结了,人生是很难完全感同身受的,唯有降低预设的基准让事情从头理清楚,害怕了我们就先休息,有车了我们就停下,先适应完全没车的情况,变得更慢一点,如果这时候着急一点,反而会起到反效果,比如只是说不要怕,接着开,甚至有点厌烦了,那基本这个练车也不太成得了了,而正好是有耐心的一起慢慢练习,还有就是第二件是切身体会,就是当道路本来是两条道,但是封了一条的时候,这时候开车如果是像我这样的新手,如果开车时左右边看着的话,车肯定开不好,因为那样会一直左右调整,反而更容易控制不好左右的距离,蹭到旁边的隔离栏,正确的方式应该是专注于正前方的路,这样才能保证左右边距离尽可能均匀,而不是顾左失右或者顾右失左,所以很多陪伴学习需要注意的是方式和耐心,能够识别到关键点那是最好的,但是有时候更需要的是耐心,纯靠耐心不一定能解决问题,但是可能会找到问题关键点。

]]>
- Java - Thread dump - 问题排查 - 工具 + 生活 - Java - Thread dump + 生活 + +
+ + 聊聊我的远程工作体验 + /2022/06/26/%E8%81%8A%E8%81%8A%E6%88%91%E7%9A%84%E8%BF%9C%E7%A8%8B%E5%B7%A5%E4%BD%9C%E4%BD%93%E9%AA%8C/ + 发生疫情之后,因为正好是春节假期,假期结束的时候还不具备回工作地点办公的条件,所以史无前例地开始了远程办公,以前对于远程办公的概念还停留在国外一些有“格局”的企业会允许员工远程办公,当然对于远程办公这个事情本身我个人也并不是全然支持的态度,其中涉及到很多方面,首先远程办公并不代表就是不用去办公地点上班,可以在家里摸鱼,相对能够得到较高报酬的能够远程办公的企业需要在远程办公期间能够有高效的产出,并且也需要像在公司办公地点一样,能随时被联系到,第二点是薪资福利之外的社保公积金,除非薪资相比非远程办公的企业高出比较多,不然没法 cover 企业额外缴纳的社保公积金,听说有部分企业也会远程办公点给员工上社保,但是毕竟能做到这点的很少,在允许远程办公的企业数量这个本来就不大的基数里,大概率是少之又少了。
疫情这个特殊原因开始的远程办公体验也算是开了个之前不太容易开的头,也跟我前面说的第一点有关系,大部分的企业也会担心员工远程办公是否有与在公司办公地点办公一样或者比较接近的办公效率。同时我们在开始远程办公的时候也碰到了因为原先没做过相应准备而导致的许多问题,首先基础设施上就有几个问题,第一个是办公电脑的问题,因为整个公司各个部门的工作性质和内容不同,并不是每个部门都是配笔记本的,或者有些部门并不需要想研发一样带上电脑 on call,所以那么使用台式机或者没有将笔记本带回家的则需要自己准备电脑或者让公司邮寄。第二个是远程网络的问题,像我们公司有研发团队平时也已经准备好了 vpn,但是在这种时候我们没准备好的是 vpn 带宽,毕竟平时只会偶尔有需要连一下 vpn 到公司网络,像这样大量员工都需要连接 vpn 进行工作的话,我们的初步体验就是网络卡的不行,一些远程调试工作没法进行,并且还有一些问题是可能只有我们研发会碰到,比如我们的线上测试服务器网络在办公地点是有网络打通的,但是我们在家就没办法连接,还有就是沟通效率相关,因为这是个全国性的情况,线上会议工具原先都是为特定用户使用,并且视频音频实时传输所需要的带宽质量要求也是比较高的,大规模的远程会议沟通需求让这些做线上会议的服务也算是碰上了类似双十一的大考了,我们是先后使用了 zoom,腾讯会议跟钉钉视频会议,使用体验上来说是 zoom 做得相对比较成熟和稳定,不过后面腾讯会议跟钉钉视频会议也开始赶上来。
前面说的这几个点都是得有远程办公经验的公司才会提前做好相应的准备,比如可以做动态网络扩容,能够在需要大量员工连接公司网络的情况下快速响应提升带宽,另一些则是偏软性的,比如如如何在远程办公的条件下控制我们项目进度,如果保证沟通信息是否能像当面沟通那样准确传达,这方面其实我的经验也是边实操边优化的,最开始我们可能为了高效同步消息,会频繁的使用视频会议沟通,这其实并不能解决沟通效率问题,反而打扰了正常的工作,后续我们在特别是做项目过程中就通过相对简单的每日早会和日报机制,将每天的进度与问题风险点进行同步确认,只与相关直接干系人进行视频电话沟通确认,并且要保持一个思维,即远程办公比较适宜的是相对比较成熟的团队,平常工作和合作都已经有默契或者说规则并且能够遵守,在这个前提下,将目光专注于做的事情而不是管到具体的人有没有全天都在高效工作。同样也希望国内的环境能够有更多的远程火种成长起来,让它成为更好的工作方式,WLB!

+]]>
+ + 生活 + + + 生活 + 远程办公
@@ -18006,16 +17995,17 @@ $ - 聊聊我的远程工作体验 - /2022/06/26/%E8%81%8A%E8%81%8A%E6%88%91%E7%9A%84%E8%BF%9C%E7%A8%8B%E5%B7%A5%E4%BD%9C%E4%BD%93%E9%AA%8C/ - 发生疫情之后,因为正好是春节假期,假期结束的时候还不具备回工作地点办公的条件,所以史无前例地开始了远程办公,以前对于远程办公的概念还停留在国外一些有“格局”的企业会允许员工远程办公,当然对于远程办公这个事情本身我个人也并不是全然支持的态度,其中涉及到很多方面,首先远程办公并不代表就是不用去办公地点上班,可以在家里摸鱼,相对能够得到较高报酬的能够远程办公的企业需要在远程办公期间能够有高效的产出,并且也需要像在公司办公地点一样,能随时被联系到,第二点是薪资福利之外的社保公积金,除非薪资相比非远程办公的企业高出比较多,不然没法 cover 企业额外缴纳的社保公积金,听说有部分企业也会远程办公点给员工上社保,但是毕竟能做到这点的很少,在允许远程办公的企业数量这个本来就不大的基数里,大概率是少之又少了。
疫情这个特殊原因开始的远程办公体验也算是开了个之前不太容易开的头,也跟我前面说的第一点有关系,大部分的企业也会担心员工远程办公是否有与在公司办公地点办公一样或者比较接近的办公效率。同时我们在开始远程办公的时候也碰到了因为原先没做过相应准备而导致的许多问题,首先基础设施上就有几个问题,第一个是办公电脑的问题,因为整个公司各个部门的工作性质和内容不同,并不是每个部门都是配笔记本的,或者有些部门并不需要想研发一样带上电脑 on call,所以那么使用台式机或者没有将笔记本带回家的则需要自己准备电脑或者让公司邮寄。第二个是远程网络的问题,像我们公司有研发团队平时也已经准备好了 vpn,但是在这种时候我们没准备好的是 vpn 带宽,毕竟平时只会偶尔有需要连一下 vpn 到公司网络,像这样大量员工都需要连接 vpn 进行工作的话,我们的初步体验就是网络卡的不行,一些远程调试工作没法进行,并且还有一些问题是可能只有我们研发会碰到,比如我们的线上测试服务器网络在办公地点是有网络打通的,但是我们在家就没办法连接,还有就是沟通效率相关,因为这是个全国性的情况,线上会议工具原先都是为特定用户使用,并且视频音频实时传输所需要的带宽质量要求也是比较高的,大规模的远程会议沟通需求让这些做线上会议的服务也算是碰上了类似双十一的大考了,我们是先后使用了 zoom,腾讯会议跟钉钉视频会议,使用体验上来说是 zoom 做得相对比较成熟和稳定,不过后面腾讯会议跟钉钉视频会议也开始赶上来。
前面说的这几个点都是得有远程办公经验的公司才会提前做好相应的准备,比如可以做动态网络扩容,能够在需要大量员工连接公司网络的情况下快速响应提升带宽,另一些则是偏软性的,比如如如何在远程办公的条件下控制我们项目进度,如果保证沟通信息是否能像当面沟通那样准确传达,这方面其实我的经验也是边实操边优化的,最开始我们可能为了高效同步消息,会频繁的使用视频会议沟通,这其实并不能解决沟通效率问题,反而打扰了正常的工作,后续我们在特别是做项目过程中就通过相对简单的每日早会和日报机制,将每天的进度与问题风险点进行同步确认,只与相关直接干系人进行视频电话沟通确认,并且要保持一个思维,即远程办公比较适宜的是相对比较成熟的团队,平常工作和合作都已经有默契或者说规则并且能够遵守,在这个前提下,将目光专注于做的事情而不是管到具体的人有没有全天都在高效工作。同样也希望国内的环境能够有更多的远程火种成长起来,让它成为更好的工作方式,WLB!

+ 聊聊最近平淡的生活之《花束般的恋爱》观后感 + /2021/12/31/%E8%81%8A%E8%81%8A%E6%9C%80%E8%BF%91%E5%B9%B3%E6%B7%A1%E7%9A%84%E7%94%9F%E6%B4%BB%E4%B9%8B%E3%80%8A%E8%8A%B1%E6%9D%9F%E8%88%AC%E7%9A%84%E6%81%8B%E7%88%B1%E3%80%8B%E8%A7%82%E5%90%8E%E6%84%9F/ + 周末在领导的提议下看了豆瓣的年度榜单,本来感觉没啥心情看的,看到主演有有村架纯就觉得可以看一下,颜值即正义嘛,男主小麦跟女主小娟(后面简称小麦跟小娟)是两个在一次非常偶然的没赶上地铁末班车事件中相识,这里得说下日本这种通宵营业的店好像挺不错的,看着也挺正常,国内估计只有酒吧之类的可以。晚上去的地方是有点暗暗的,好像也有点类似酒吧,旁边有类似于 dj 那种,然后同桌的还有除了男女主的另外一对男女,也是因为没赶上地铁末班车的,但也是陌生人,然后小麦突然看到了有个非常有名的电影人,小娟竟然也认识,然后旁边那对完全不认识,还在那吹自己看过很多电影,比如《肖申克的救赎》,于是男女主都特别鄙夷地看着他们,然后他们又去了另一个有点像泡澡的地方席地而坐,他们发现了自己的鞋子都是一样的,然后在女的去上厕所的时候,小麦暗恋的学姐也来了,然后小麦就去跟学姐他们一起坐了,小娟回来后有点不开心就说去朋友家睡,幸好小麦看出来了(他竟然看出来了,本来以为应该是没填过恋爱很木讷的),就追出去,然后就去了小麦家,到了家小娟发现小麦家的书柜上的书简直就跟她自己家的一模一样,小麦还给小娟吹了头发,一起吃烤饭团,看电影,第二天送小娟上了公交,还约好了一起看木乃伊展,然而并没有交换联系方式,但是他们还是约上了一起看了木乃伊展,在餐馆就出现了片头那一幕的来源,因为餐馆他们想一起听歌,就用有线耳机一人一个耳朵听,但是旁边就有个大叔说“你们是不是不爱音乐,左右耳朵是不一样的,只有一起听才是真正的音乐”这样的话,然后的剧情有点跳,因为是指他们一直在这家餐馆吃饭,中间有他们一起出去玩情节穿插着,也是在这他们确立了关系,可以说主体就是体现了他们非常的合拍和默契,就像一些影评说的,这部电影是说如何跟百分百合拍的人分手,然后就是正常的恋爱开始啪啪啪,一直腻在床上,也没去就业说明会,后面也有讲了一点小麦带着小娟去认识他的朋友,也把小娟介绍给了他们认识,这里算是个小伏笔,后面他们分手也有这里的人的一些关系,接下去的剧情说实话我是不太喜欢的,如果一部八分的电影只是说恋爱被现实打败的话,我觉得在我这是不合格的,但是事实也是这样,小麦其实是有家里的资助,所以后面还是按自己的喜好给一些机构画点插画,小娟则要出去工作,因为小娟家庭观念也是要让她出去有正经工作,用脚指头想也能知道肯定不顺利,然后就是暂时在一家蛋糕店工作,小麦就每天去接小娟,日子过得甜甜蜜蜜,后面小娟在自己的努力下考了个什么资格证,去了一家医院还是什么做前台行政,这中间当然就有父母来见面吃饭了,他们在开始恋爱不久就同居合租了,然后小娟父母就是来说要让她有个正经工作,对男的说的话就是人生就是责任这类的话,而小麦爸爸算是个导火索,因为小麦家里是做烟花生意的,他爸让他就做烟花生意,因为要回老家,并且小麦也不想做,所以就拒绝了,然后他爸就说不给他每个月五万的资助,这也导致了小麦需要去找工作,这个过程也是很辛苦,本来想要年前找好工作,然后事与愿违,后面有一次小娟被同事吐槽怎么从来不去团建,于是她就去了(我以为会拒绝),正在团建的时候小麦给她电话,说找到工作了,是一个创业物流公司这种,这里剧情就是我觉得比较俗套的,小麦各种被虐,累成狗,但是就像小娟爸爸说的话,人生就是责任,所以一直在坚持,但是这样也导致了跟小娟的交流也越来越少,他们原来最爱的漫画,爱玩的游戏,也只剩小娟一个人看,一个人玩,而正是这个时候,小娟说她辞掉了工作,去做一个不是太靠谱的漫画改造的密室逃脱,然后这里其实有一点后面争议很大的,就是这个工作其实是前面小麦介绍给小娟的那些朋友中一个的女朋友介绍的,而在有个剧情就是小娟有一次在这个密室逃脱的老板怀里醒过来,是在 KTV 那样的场景里,这就有很多人觉得小娟是不是出轨了,我觉得其实不那么重要,因为这个离职的事情已经让一切矛盾都摆在眼前,小麦其实是接受这种需要承担责任的生活,也想着要跟小娟结婚,但是小娟似乎还是想要过着那样理想的生活,做自己想做的事情,看自己爱看的漫画,也要小麦能像以前那样一直那么默契的有着相同的爱好,这里的触发点其实还有个是那个小麦的朋友(也就是他女朋友介绍小娟那个不靠谱工作的)的葬礼上,小麦在参加完葬礼后有挺多想倾诉的,而小娟只是想睡了,这个让小麦第二天起来都不想理小娟,只是这里我不太理解,难道这点闹情绪都不能接受吗,所谓的合拍也只是毫无限制的情况下的合拍吧,真正的生活怎么可能如此理想呢,即使没有物质生活的压力,也会有其他的各种压力和限制,在这之后其实小麦想说的是小娟是不是没有想跟自己继续在一起的想法了,而小娟觉得都不说话了,还怎么结婚呢,后面其实导演搞了个小 trick,突然放了异常婚礼,但是不是男女主的,我并不觉得这个桥段很好,在婚礼里男女主都觉得自己想要跟对方说分手了,但是当他们去了最开始一直去的餐馆的时候,一个算是一个现实映照的就是他们一直坐的位子被占了,可能也是导演想通过这个来说明他们已经回不去了,在餐馆交谈的时候,小麦其实是说他们结婚吧,并没有想前面婚礼上预设地要分手,但是小娟放弃了,不想结婚,因为不想过那样的生活了,而小麦觉得可能生活就是那样,不可能一直保持刚恋爱时候的那种感觉,生活就是责任,人生就意味着责任。

+

我的一些观点也在前面说了,恋爱到婚姻,即使物质没问题,经济没问题,也会有各种各样的问题,需要一起去解决,因为结婚就意味着需要相互扶持,而不是各取所需,可能我的要求比较高,后面男女主在分手后还一起住了一段时间,我原来还在想会不会通过这个方式让他们继续去磨合同步,只是我失望了,最后给个打分可能是 5 到 6 分吧,勉强及格,好的影视剧应该源于生活高于生活,这一部可能还比不上生活。

]]>
生活 生活 - 远程办公 + 看剧
@@ -18038,92 +18028,337 @@ $ - 聊聊最近平淡的生活之《花束般的恋爱》观后感 - /2021/12/31/%E8%81%8A%E8%81%8A%E6%9C%80%E8%BF%91%E5%B9%B3%E6%B7%A1%E7%9A%84%E7%94%9F%E6%B4%BB%E4%B9%8B%E3%80%8A%E8%8A%B1%E6%9D%9F%E8%88%AC%E7%9A%84%E6%81%8B%E7%88%B1%E3%80%8B%E8%A7%82%E5%90%8E%E6%84%9F/ - 周末在领导的提议下看了豆瓣的年度榜单,本来感觉没啥心情看的,看到主演有有村架纯就觉得可以看一下,颜值即正义嘛,男主小麦跟女主小娟(后面简称小麦跟小娟)是两个在一次非常偶然的没赶上地铁末班车事件中相识,这里得说下日本这种通宵营业的店好像挺不错的,看着也挺正常,国内估计只有酒吧之类的可以。晚上去的地方是有点暗暗的,好像也有点类似酒吧,旁边有类似于 dj 那种,然后同桌的还有除了男女主的另外一对男女,也是因为没赶上地铁末班车的,但也是陌生人,然后小麦突然看到了有个非常有名的电影人,小娟竟然也认识,然后旁边那对完全不认识,还在那吹自己看过很多电影,比如《肖申克的救赎》,于是男女主都特别鄙夷地看着他们,然后他们又去了另一个有点像泡澡的地方席地而坐,他们发现了自己的鞋子都是一样的,然后在女的去上厕所的时候,小麦暗恋的学姐也来了,然后小麦就去跟学姐他们一起坐了,小娟回来后有点不开心就说去朋友家睡,幸好小麦看出来了(他竟然看出来了,本来以为应该是没填过恋爱很木讷的),就追出去,然后就去了小麦家,到了家小娟发现小麦家的书柜上的书简直就跟她自己家的一模一样,小麦还给小娟吹了头发,一起吃烤饭团,看电影,第二天送小娟上了公交,还约好了一起看木乃伊展,然而并没有交换联系方式,但是他们还是约上了一起看了木乃伊展,在餐馆就出现了片头那一幕的来源,因为餐馆他们想一起听歌,就用有线耳机一人一个耳朵听,但是旁边就有个大叔说“你们是不是不爱音乐,左右耳朵是不一样的,只有一起听才是真正的音乐”这样的话,然后的剧情有点跳,因为是指他们一直在这家餐馆吃饭,中间有他们一起出去玩情节穿插着,也是在这他们确立了关系,可以说主体就是体现了他们非常的合拍和默契,就像一些影评说的,这部电影是说如何跟百分百合拍的人分手,然后就是正常的恋爱开始啪啪啪,一直腻在床上,也没去就业说明会,后面也有讲了一点小麦带着小娟去认识他的朋友,也把小娟介绍给了他们认识,这里算是个小伏笔,后面他们分手也有这里的人的一些关系,接下去的剧情说实话我是不太喜欢的,如果一部八分的电影只是说恋爱被现实打败的话,我觉得在我这是不合格的,但是事实也是这样,小麦其实是有家里的资助,所以后面还是按自己的喜好给一些机构画点插画,小娟则要出去工作,因为小娟家庭观念也是要让她出去有正经工作,用脚指头想也能知道肯定不顺利,然后就是暂时在一家蛋糕店工作,小麦就每天去接小娟,日子过得甜甜蜜蜜,后面小娟在自己的努力下考了个什么资格证,去了一家医院还是什么做前台行政,这中间当然就有父母来见面吃饭了,他们在开始恋爱不久就同居合租了,然后小娟父母就是来说要让她有个正经工作,对男的说的话就是人生就是责任这类的话,而小麦爸爸算是个导火索,因为小麦家里是做烟花生意的,他爸让他就做烟花生意,因为要回老家,并且小麦也不想做,所以就拒绝了,然后他爸就说不给他每个月五万的资助,这也导致了小麦需要去找工作,这个过程也是很辛苦,本来想要年前找好工作,然后事与愿违,后面有一次小娟被同事吐槽怎么从来不去团建,于是她就去了(我以为会拒绝),正在团建的时候小麦给她电话,说找到工作了,是一个创业物流公司这种,这里剧情就是我觉得比较俗套的,小麦各种被虐,累成狗,但是就像小娟爸爸说的话,人生就是责任,所以一直在坚持,但是这样也导致了跟小娟的交流也越来越少,他们原来最爱的漫画,爱玩的游戏,也只剩小娟一个人看,一个人玩,而正是这个时候,小娟说她辞掉了工作,去做一个不是太靠谱的漫画改造的密室逃脱,然后这里其实有一点后面争议很大的,就是这个工作其实是前面小麦介绍给小娟的那些朋友中一个的女朋友介绍的,而在有个剧情就是小娟有一次在这个密室逃脱的老板怀里醒过来,是在 KTV 那样的场景里,这就有很多人觉得小娟是不是出轨了,我觉得其实不那么重要,因为这个离职的事情已经让一切矛盾都摆在眼前,小麦其实是接受这种需要承担责任的生活,也想着要跟小娟结婚,但是小娟似乎还是想要过着那样理想的生活,做自己想做的事情,看自己爱看的漫画,也要小麦能像以前那样一直那么默契的有着相同的爱好,这里的触发点其实还有个是那个小麦的朋友(也就是他女朋友介绍小娟那个不靠谱工作的)的葬礼上,小麦在参加完葬礼后有挺多想倾诉的,而小娟只是想睡了,这个让小麦第二天起来都不想理小娟,只是这里我不太理解,难道这点闹情绪都不能接受吗,所谓的合拍也只是毫无限制的情况下的合拍吧,真正的生活怎么可能如此理想呢,即使没有物质生活的压力,也会有其他的各种压力和限制,在这之后其实小麦想说的是小娟是不是没有想跟自己继续在一起的想法了,而小娟觉得都不说话了,还怎么结婚呢,后面其实导演搞了个小 trick,突然放了异常婚礼,但是不是男女主的,我并不觉得这个桥段很好,在婚礼里男女主都觉得自己想要跟对方说分手了,但是当他们去了最开始一直去的餐馆的时候,一个算是一个现实映照的就是他们一直坐的位子被占了,可能也是导演想通过这个来说明他们已经回不去了,在餐馆交谈的时候,小麦其实是说他们结婚吧,并没有想前面婚礼上预设地要分手,但是小娟放弃了,不想结婚,因为不想过那样的生活了,而小麦觉得可能生活就是那样,不可能一直保持刚恋爱时候的那种感觉,生活就是责任,人生就意味着责任。

-

我的一些观点也在前面说了,恋爱到婚姻,即使物质没问题,经济没问题,也会有各种各样的问题,需要一起去解决,因为结婚就意味着需要相互扶持,而不是各取所需,可能我的要求比较高,后面男女主在分手后还一起住了一段时间,我原来还在想会不会通过这个方式让他们继续去磨合同步,只是我失望了,最后给个打分可能是 5 到 6 分吧,勉强及格,好的影视剧应该源于生活高于生活,这一部可能还比不上生活。

+ 聊聊我刚学会的应用诊断方法 + /2020/05/22/%E8%81%8A%E8%81%8A%E6%88%91%E5%88%9A%E5%AD%A6%E4%BC%9A%E7%9A%84%E5%BA%94%E7%94%A8%E8%AF%8A%E6%96%AD%E6%96%B9%E6%B3%95/ + 因为传说中的出身问题,我以前写的是PHP,在使用 swoole 之前,基本的应用调试手段就是简单粗暴的 var_dump,exit,对于单进程模型的 PHP 也是简单有效,技术栈换成 Java 之后,就变得没那么容易,一方面是需要编译,另一方面是一般都是基于 spring 的项目,如果问题定位比较模糊,那框架层的是很难靠简单的 System.out.println 或者打 log 解决,(PS:我觉得可能我写的东西比较适合从 PHP 这种弱类型语言转到 Java 的小白同学)这个时候一方面因为是 Java,有了非常好用的 idea IDE 的支持,可以各种花式调试,条件断点尤其牛叉,但是又因为有 Spring+Java 的双重原因,有些情况下单步调试可以把手按废掉,这也是我之前一直比较困惑苦逼的点,后来随着慢慢精(jiang)进(you)之后,比如对于一个 oom 的情况,我们可以通过启动参数加上-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=xx/xx 来配置溢出时的堆dump 日志,获取到这个文件后,我们可以通过像 Memory Analyzer (MAT)[https://www.eclipse.org/mat/] (The Eclipse Memory Analyzer is a fast and feature-rich Java heap analyzer that helps you find memory leaks and reduce memory consumption.)来查看诊断问题所在,之前用到的时候是因为有个死循环一直往链表里塞数据,属于比较简单的,后来一次是由于运维进行应用迁移时按默认的统一配置了堆内存大小,导致内存的确不够用,所以溢出了,
今天想说的其实主要是我们的 thread dump,这也是我最近才真正用的一个方法,可能真的很小白了,用过 ide 的单步调试其实都知道会有一个一层层的玩意,比如函数从 A,调用了 B,再从 B 调用了 C,一直往下(因为是 Java,所以还有很多🤦‍♂️),这个其实也是大部分语言的调用模型,利用了栈这个数据结构,通过这个结构我们可以知道代码的调用链路,由于对于一个 spring 应用,在本身框架代码量非常庞大的情况下,外加如果应用代码也是非常多的时候,有时候通过单步调试真的很难短时间定位到问题,需要非常大的耐心和仔细观察,当然不是说完全不行,举个例子当我的应用经常启动需要非常长的时间,因为本身应用有非常多个 bean,比较难说究竟是 bean 的加载的确很慢还是有什么异常原因,这种时候就可以使用 thread dump 了,具体怎么操作呢

如果在idea 中运行或者调试时,可以直接点击这个照相机一样的按钮,右边就会出现了左边会显示所有的线程,右边会显示线程栈,

+
"main@1" prio=5 tid=0x1 nid=NA runnable
+  java.lang.Thread.State: RUNNABLE
+	  at TreeDistance.treeDist(TreeDistance.java:64)
+	  at TreeDistance.treeDist(TreeDistance.java:65)
+	  at TreeDistance.treeDist(TreeDistance.java:65)
+	  at TreeDistance.treeDist(TreeDistance.java:65)
+	  at TreeDistance.main(TreeDistance.java:45)
+

这就是我们主线程的堆栈信息了,main 表示这个线程名,prio表示优先级,默认是 5,tid 表示线程 id,nid 表示对应的系统线程,后面的runnable 表示目前线程状态,因为是被我打了断点,所以是就许状态,然后下面就是对应的线程栈内容了,在TreeDistance类的 treeDist方法中,对应的文件行数是 64 行。
这里使用 thread dump一般也不会是上面我截图代码里的这种代码量很少的,一般是大型项目,有时候跑着跑着没反应,又不知道跑到哪了,特别是一些刚接触的大项目或者需要定位一个大项目的一个疑难问题,一时没思路时,可以使用这个方法,个人觉得非常有帮助。

+]]>
+ + Java + Thread dump + 问题排查 + 工具 + + + Java + Thread dump + +
+ + 聊聊最近平淡的生活之看看老剧 + /2021/11/21/%E8%81%8A%E8%81%8A%E6%9C%80%E8%BF%91%E5%B9%B3%E6%B7%A1%E7%9A%84%E7%94%9F%E6%B4%BB%E4%B9%8B%E7%9C%8B%E7%9C%8B%E8%80%81%E5%89%A7/ + 最近因为也没什么好看的新剧和综艺所以就看看一些以前看过的老剧,我是个非常念旧的人吧,很多剧都会反反复复地看,一方面之前看过觉得好看的的确是一直记着,还有就是平时工作完了回来就想能放松下,剧情太纠结的,太烧脑的都不喜欢,也就是我常挂在口头的不喜欢看费脑子的剧,跟我不喜欢狼人杀的原因也类似。

+

前面其实是看的太阳的后裔,跟 LD 一起看的,之前其实算是看过一点,但是没有看的很完整,并且很多剧情也忘了,只是这个我我可能看得更少一点,因为最开始的时候觉得男主应该是男二,可能对长得这样的男主并且是这样的人设有点失望,感觉不是特别像个特种兵,但是由于本来也比较火,而且 LD 比较喜欢就从这个开始看了,有两个点是比较想说的

+

韩剧虽然被吐槽的很多,但是很多剧的质量,情节把控还是优于目前非常多国内剧的,相对来说剧情发展的前后承接不是那么硬凹出来的,而且人设都立得住,这个是非常重要的,很多国内剧怎么说呢,就是当爹的看起来就比儿子没大几岁,三四十岁的人去演一个十岁出头的小姑娘,除非容貌异常,比如刘晓庆这种,不然就会觉得导演在把我们观众当傻子。瞬间就没有想看下去的欲望了。

+

再一点就是情节是大众都能接受度比较高的,现在有很多普遍会找一些新奇的视角,比如卖腐,想某某令,两部都叫某某令,这其实是一个点,延伸出去就是跟前面说的一点有点类似,xx 老祖,人看着就二三十,叫 xx 老祖,(喜欢的人轻喷哈)然后名字有一堆,同一个人物一会叫这个名字,一会又叫另一个名字,然后一堆死表情。

+

因为今天有个特殊的事情发生,所以简短的写(shui)一篇了

+]]>
+ + 生活 + + + 生活 + 看剧 + +
+ + 聊聊最近平淡的生活之看《神探狄仁杰》 + /2021/12/19/%E8%81%8A%E8%81%8A%E6%9C%80%E8%BF%91%E5%B9%B3%E6%B7%A1%E7%9A%84%E7%94%9F%E6%B4%BB%E4%B9%8B%E7%9C%8B%E3%80%8A%E7%A5%9E%E6%8E%A2%E7%8B%84%E4%BB%81%E6%9D%B0%E3%80%8B/ + 其实最近看的不止这一部,前面看了《继承者们》,《少年包青天》这些,就一起聊下,其中看《继承者们》算是个人比较喜欢,以前就有这种看剧的习惯,这个跟《一生一世》里任嘉伦说自己看《寻秦记》看了几十遍一样,我看喜欢的剧也基本上会看不止五遍,继承者们是有帅哥美女看,而且印象中剧情也挺甜的,一般情况下最好是已经有点遗忘剧情了,因为我个人觉得看剧分两种,无聊了又心情不太好,可以看些这类轻松又看过的剧,可以不完全专心地看剧,另外有心情专心看的时候,可以看一些需要思考,一些探案类的或者烧脑类。
最近看了《神探狄仁杰》,因为跟前面看的《少年包青天》都是这类古装探案剧,正好有些感想,《少年包青天》算是儿时阴影,本来是不太会去看的,正好有一次有机会跟 LD 一起看了会就也觉得比较有意思就看了下去,不得不说,以前的这些剧还是很不错的,包括剧情和演员,第一部一共是 40 集,看的过程中也发现了大概是五个案子,平均八集一个案子,整体节奏还是比较慢的,但是基本每个案子其实都是构思得很巧妙,很久以前看过但是现在基本不太记得剧情了,每个案子在前面几集的时候基本都猜不到犯案逻辑,但是在看了狄仁杰之后,发现两部剧也有比较大的差别,少年包青天相对来说逻辑性会更强一些,个人主观觉得推理的严谨性更高,可能剧本打磨上更将就一下,而狄仁杰因为要提现他的个人强项,不比少年包青天中有公孙策一时瑜亮的情节,狄仁杰中分工明确,李元芳是个武力担当,曾泰是捧哏的,相对来说是狄仁杰在案子里从始至终地推进案情,有些甚至有些玄乎,会有一些跳脱跟不合理,有些像是狄仁杰的奇遇,不过这些想法是私人的观点,并不是想要评孰优孰劣;第二个感受是不知道是不是年代关系,特别是少年包青天,每个案件的大 boss 基本都不是个完全的坏人,甚至都是比较情有可原的可怜人,因为一些特殊原因,而好几个都是包拯身边的人,这一点其实跟狄仁杰里第一个使团惊魂案件比较类似,虎敬晖也是个人物形象比较丰满的角色,不是个标签化的淡薄形象,跟金木兰的感情和反叛行动在最后都说明的缘由,而且也有随着跟狄仁杰一起办案被其影响感化,最终为了救狄仁杰而被金木兰所杀,只是这样金木兰这个角色就会有些偏执和符号化,当然剧本肯定不是能面面俱到,这样的剧本已经比现在很多流量剧的好很多了。还想到了前阵子看的《指环王》中的白袍萨鲁曼在剧中也是个比较单薄的角色,这样的电影彪炳影史也没办法把个个人物都设计得完整有血有肉,或者说这本来也是应该有侧重点,当然其实我也不觉得指环王就是绝对的最好的,因为相对来说故事情节的复杂性等真的不如西游记,只是在 86 版之后的各种乱七八糟的翻牌和乱拍已经让这个真正的王者神话故事有点力不从心,这里边有部西游记后传是个人还比较喜欢的,虽然武打动作比较鬼畜,但是剧情基本是无敌的,在西游的架构上衍生出来这么完整丰富的故事,人物角色也都有各自的出彩点。
说回狄仁杰,在这之前也看过徐克拍的几部狄仁杰的电影版,第一部刘德华拍得相对完成度更高,故事性也可圈可点,后面几部就是剧情拉胯,靠特效拉回来一点分,虽说这个也是所谓的狄仁杰宇宙的构思在里面但是现在来看基本是跟西游那些差不多,完全没有整体性可言,打一枪换一个地方,演员也没有延续性,剧情也是前后跳脱,没什么关联跟承上启下,导致质量层次不一,更不用谈什么狄仁杰宇宙了,不过这个事情也是难说,原因很多,现在资本都是更加趋利的,一些需要更长久时间才能有回报的投资是很难获得资本青睐,所以只能将重心投给选择一些流量明星,而本来应该将资源投给剧本打磨的基本就没了,再深入说也没意义了,社会现状就是这样。
还有一点感想是,以前的剧里的拍摄环境还是比较惨的,看着一些房子,甚至皇宫都是比较破旧的,地面还是石板这种,想想以前的演员的环境再想想现在的,比如成龙说的,以前他拍剧就是啪摔了,问这条有没有过,过了就直接送医院,而不是现在可能手蹭破点皮就大叫,甚至还有饭圈这些破事。

+]]>
+ + 生活 + + + 生活 + 看剧 + +
+ + 聊聊部分公交车的设计bug + /2021/12/05/%E8%81%8A%E8%81%8A%E9%83%A8%E5%88%86%E5%85%AC%E4%BA%A4%E8%BD%A6%E7%9A%84%E8%AE%BE%E8%AE%A1bug/ + 今天惯例坐公交回住的地方,不小心撞了头,原因是我们想坐倒数第二排,然后LD 走在我后面,我就走到最后一排中间等着,但是最后一排是高一截的,等 LD 坐进去以后,我就往前走,结果撞到了车顶的扶手杆子的一端,差点撞昏了去,这里我觉得其实杆子长度应该短一点,不然从最后一排出来,还是有比较大概率因为没注意看而撞到头,特别是没注意看的情况,发力其实会比较大,一头撞上就会像我这样,眼前一黑,又痛得要死。
还有一点就是座位设计了,先来看个图

图里大致画了两条线,因为可能是轮胎还是什么原因,后排中间会有那么大的突起,但是看两条红线可以发现,靠近过道的座位边缘跟地面突起的边缘不是一样宽的,这样导致的结果就是坐着的时候有一个脚没地儿搁,要不就得侧着斜着坐,或者就是一个脚悬空,短程的可能还好,路程远一点还是比较难受的,特别是像我现在这样,大腿外侧有点难受的情况,就会更难受。
虽然说这两个点,基本是屁用没有,但是我也是在自己这个博客说说,也当是个树洞了。

+]]>
+ + 生活 + + + 生活 + 公交 + 杭州 + +
+ + 聊聊那些加塞狗 + /2021/01/17/%E8%81%8A%E8%81%8A%E9%82%A3%E4%BA%9B%E5%8A%A0%E5%A1%9E%E7%8B%97/ + 今天真的是被气得不轻,情况是碰到一个有 70 多秒的直行红灯,然后直行就排了很长的队,但是左转车道没车,就有好几辆车占着左转车道,准备往直行车道插队加塞,一般这种加塞的,会挑个不太计较的,如果前面一辆不让的话就再等等,我因为赶着回家,就不想让,结果那辆车几次车头直接往里冲,当时怒气值基本已经蓄满了,我真的是分毫都不想让,如果路上都是让着这种人的,那么这种情况只会越来越严重,我理解的这种心态,就赌你怕麻烦,多一事不如少一事,结果就是每次都能顺利插队加塞,其实延伸到我们社会中的种种实质性的排队或者等同于排队的情况,都已经有这种惯有思维,一方面这种不符合规则,可能在严重程度上容易被很多人所忽视,基本上已经被很多人当成是“合理”行为,另一方面,对于这些“微小”的违规行为,本身管理层面也基本没有想要管的意思,就更多的成为了纵容这些行为的导火索,并且大多数人都是想着如果不让,发生点小剐小蹭的要浪费很多时间精力来处理,甚至会觉得会被别人觉得自己太小气等等,诸多内外成本结合起来,会真的去硬刚的可能少之又少了,这样也就让更多的人觉得这种行为是被默许的,再举个非常小的例子,以我们公司疫情期间的盒饭发放为例,有两个比较“有意思”的事情,第一个就是因为疫情,本来是让排队要间隔一米,但是可能除了我比较怕死会跟前面的人保持点距离基本没别人会不挨着前面的人,甚至我跟我前面的人保持点距离,后面的同学会推着我让我上去;第二个是关于拿饭,这么多人排着队拿饭,然后有部分同学,一个人拿好几份,帮组里其他人的都拿了,有些甚至一个人拿十份,假如这个盒饭发放是说明了可以按部门直接全领了那就没啥问题,但是当时的状况是个人排队领自己的那一份,如果一个同学直接帮着组里十几个人都拿了,后面排队的人是什么感受呢,甚至有些是看到队伍排长了,就找队伍里自己认识的比较靠前的人说你帮我也拿一份,其实作为我这个比较按规矩办事的“愣头青”来说,我是比较不能接受这两件小事里的行为的,再往下说可能就有点偏激了,先说到这~

+]]>
+ + 生活 + 开车 + + + 生活 + 开车 + 加塞 + 糟心事 + 规则 + +
+ + 聊聊给亲戚朋友的老电脑重装系统那些事儿 + /2021/05/09/%E8%81%8A%E8%81%8A%E7%BB%99%E4%BA%B2%E6%88%9A%E6%9C%8B%E5%8F%8B%E7%9A%84%E8%80%81%E7%94%B5%E8%84%91%E9%87%8D%E8%A3%85%E7%B3%BB%E7%BB%9F%E9%82%A3%E4%BA%9B%E4%BA%8B%E5%84%BF/ + 前面这个五一回去之前,LD 姐姐跟我说电脑很卡了,想让我重装系统,问了下 LD 可能是那个 09 年买的笔记本,想想有点害怕[捂脸],前年有一次好像让我帮忙装了她同事的一个三星的笔记本,本着一些系统洁癖,所以就从开始找纯净版的 win7 家庭版,因为之前那些本基本都自带 win7 的家庭版,而且把激活码就贴在机器下面,然后从三星官网去找官方驱动,还好这个机型的驱动还在,先做了系统镜像,其实感觉这种情况需要两个 U 盘,一个 U 盘装系统作为安装启动盘,一个放驱动,毕竟不是专业装系统的,然后因为官方驱动需要一个个下载一个个安装,然后驱动文件下载的地方还没标明是 32 位还是 64 位的,结果还被 LD 姐姐催着,一直问好没好,略尴尬,索性还是找个一键安装的

+

这次甚至更夸张,上次还让带回去,我准备好了系统镜像啥的,第二天装,这次直接带了两个老旧笔记本过来说让当天就装好,感觉有点像被当修电脑的使,又说这些电脑其实都不用了的,都是为了她们当医生的要每年看会课,然后只能用电脑浏览器看,结果都在用 360 浏览器,真的是万恶的 360,其实以前对 360 没啥坏印象,毕竟以前也经常用,只是对于这些老电脑,360 全家桶真的就是装了就废了,2G 的内存,开机就开着 360 安全卫士,360 杀毒,有一个还装了腾讯电脑管家,然后腾讯视频跟爱奇艺也开机启动了,然后还打开 360 浏览器看课,就算再好的系统也吃不消这么用,重装了系统,还是这么装这些东西,也是分分钟变卡,可惜他们都没啥这类概念。

+

对于他们要看的课,更搞笑的是,明明在页面上注明了说要使用 IE 浏览器,结果他们都在用 360 浏览器看,但是这个也不能完全怪他们,因为实在是现在的 IE 啥的也有开始不兼容 flash 的配置,需要开启兼容配置,但是只要开启了之后就可以直接用 IE 看,比 360 靠谱很多, 资源占用也比较少,360 估计是基于 chromium 加了很多内置的插件,本身 chromium 也是内存大户,但是说这些其实他们也不懂,总觉得找我免费装下系统能撑一段时间,反正对我来说也应该很简单(他们觉得),实际上开始工作以后,我自己想装个双系统都是上淘宝买别人的服务装的,台式机更是几年没动过系统了,因为要重装一大堆软件,数据备份啥的,还有驱动什么的,分区格式,那些驱动精灵啥的也都是越来越坑,一装就给你带一堆垃圾软件。

+

感悟是,总觉得学计算机的就应该会装系统,会修电脑,之前亲戚还拿着一个完全开不起来的笔记本让我来修,这真的是,我说可以找官方维修的,结果我说我搞不定,她直接觉得是修不好了,直接电脑都懒得拿回去了,后面又一次反复解释了才明白,另外就是 360 全家桶,别说老电脑了,新机器都不太吃得消。

+]]>
+ + 生活 + + + 生活 + 装电脑 + 老电脑 + 360 全家桶 + 修电脑的 + +
+ + 聊聊这次换车牌及其他 + /2022/02/20/%E8%81%8A%E8%81%8A%E8%BF%99%E6%AC%A1%E6%8D%A2%E8%BD%A6%E7%89%8C%E5%8F%8A%E5%85%B6%E4%BB%96/ + 去年 8 月份运气比较好,摇到了车牌,本来其实应该很早就开始摇的,前面第一次换工作没注意社保断缴了一个月,也是大意失荆州,后面到了 17 年社保满两年了,好像只摇了一次,还是就没摇过,有点忘了,好像是什么原因导致那次也没摇成功,但是后面暂住证就取消了,需要居住证,居住证又要一年及以上的租房合同,并且那会买车以后也不怎么开,住的地方车位还好,但是公司车位一个月要两三千,甚至还是打车上下班比较实惠,所以也没放在心上,后面摇到房以后,也觉得应该准备起来车子,就开始办了居住证,居住证其实还可以用劳动合同,而且办起来也挺快,大概是三四月份开始摇,到 8 月份的某一天收到短信说摇到了,一开始还挺开心,不过心里抱着也不怎么开,也没怎么大放在心上,不过这里有一点就是我把那个照片直接发出去,上面有着我的身份证号,被 LD 说了一顿,以后也应该小心点,但是后面不知道是哪里看了下,说杭州上牌已经需要国六标准的车了,瞬间感觉是空欢喜了,可是有同事说是可以的,我就又打了官方的电话,结果说可以的,要先转籍,然后再做上牌。

+

转籍其实是很方便的,在交警 12123 App 上申请就行了,在转籍以后,需要去实地验车,验车的话,在支付宝-杭州交警生活号里进行预约,找就近的车管所就好,需要准备一些东西,首先是行驶证,机动车登记证书,身份证,居住证,还有车上需要准备的东西是要有三脚架和反光背心,反光背心是最近几个月开始要的,问过之前去验车的只需要三脚架就好了,预约好了的话建议是赶上班时间越早越好,不然过去排队时间要很久,而且人多了以后会很乱,各种插队,而且有很多都是汽车销售,一个销售带着一堆车,我们附近那个进去的小路没一会就堵满车,进去需要先排队,然后扫码,接着交资料,这两个都排着队,如果去晚了就要排很久的队,交完资料才是排队等验车,验车就是打开引擎盖,有人会帮忙拓印发动机车架号,然后验车的会各种检查一下,车里面,还有后备箱,建议车内整理干净点,后备箱不要放杂物,检验完了之后,需要把三脚架跟反光背心放在后备箱盖子上,人在旁边拍个照,然后需要把车牌遮住后再拍个车子的照片,再之后就是去把车牌卸了,这个多吐槽下,那边应该是本来那边师傅帮忙卸车牌,结果他就说是教我们拆,虽然也不算难,但是不排除师傅有在偷懒,完了之后就是把旧车牌交回去,然后需要在手机上(警察叔叔 App)提交各种资料,包括身份证,行驶证,机动车登记证书,提交了之后就等寄车牌过来了。

+

这里面缺失的一个环节就是选号了,选号杭州有两个方式,一种就是根据交管局定期发布的选号号段,可以自定义拼 20 个号,在手机上的交警 12123 App 上可以三个一组的形式提交,如果有没被选走的,就可以预选到这个了,但是这种就是也需要有一定策略,最新出的号段能选中的概率大一点,然后数字全是 8,6 这种的肯定会一早就被选走,然后如果跟我一样可以提前选下尾号,因为尾号数字影响限号,我比较有可能周五回家,所以得避开 5,0 的,第二种就是 50 选一跟以前新车选号一样,就不介绍了。第一种选中了以后可以在前面交还旧车牌的时候填上等着寄过来了,因为我是第一种选中的,第二种也可以在手机上选,也在可以在交还车牌的时候现场选。

+

总体过程其实是 LD 在各种查资料跟帮我跑来跑去,要不是 LD,估计在交管局那边我就懵逼了,各种插队,而且车子开着车子,也不能随便跑,所以建议办这个的时候有个人一起比较好。

+]]>
+ + 生活 + + + 生活 + 换车牌 + +
+ + 记录下 Java Stream 的一些高效操作 + /2022/05/15/%E8%AE%B0%E5%BD%95%E4%B8%8B-Java-Lambda-%E7%9A%84%E4%B8%80%E4%BA%9B%E9%AB%98%E6%95%88%E6%93%8D%E4%BD%9C/ + 我们日常在代码里处理一些集合逻辑的时候用到 Stream 其实还挺多的,普通的取值过滤集合一般都是结合 ide 的提示就能搞定了,但是有些不太常用的就在这记录下,争取后面都更新记录下来。

+

自定义 distinctByKey 对结果进行去重

stream 中自带的 distinct 只能对元素进行去重
比如下面代码

+
public static void main(String[] args) {
+        List<Integer> list = new ArrayList<>();
+        list.add(1);
+        list.add(1);
+        list.add(2);
+        list = list.stream().distinct().collect(Collectors.toList());
+        System.out.println(list);
+    }
+

结果就是去了重的

+
[1, 2]
+

但是当我的元素是个复杂对象,我想根据对象里的某个元素进行过滤的时候,就需要用到自定义的 distinctByKey 了,比如下面的想对 userId 进行去重

+
public static void main(String[] args) {
+        List<StudentRecord> list = new ArrayList<>();
+        StudentRecord s1 = new StudentRecord();
+        s1.setUserId(11L);
+        s1.setCourseId(100L);
+        s1.setScore(100);
+        list.add(s1);
+        StudentRecord s2 = new StudentRecord();
+        s2.setUserId(11L);
+        s2.setCourseId(101L);
+        s2.setScore(100);
+        list.add(s2);
+        StudentRecord s3 = new StudentRecord();
+        s3.setUserId(12L);
+        s3.setCourseId(100L);
+        s3.setScore(100);
+        list.add(s3);
+        System.out.println(list.stream().distinct().collect(Collectors.toList()));
+    }
+    @Data
+    static class StudentRecord {
+        Long id;
+        Long userId;
+        Long courseId;
+        Integer score;
+    }
+

结果就是

+
[StudentRecord(id=null, userId=11, courseId=100, score=100), StudentRecord(id=null, userId=11, courseId=101, score=100), StudentRecord(id=null, userId=12, courseId=100, score=100)]
+

因为对象都不一样,所以就没法去重了,这里就需要用

+
public static <T> Predicate<T> distinctByKey(
+            Function<? super T, ?> keyExtractor) {
+
+        Map<Object, Boolean> seen = new ConcurrentHashMap<>();
+        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
+    }
+

然后就可以用它来去重了

+
System.out.println(list.stream().filter(distinctByKey(StudentRecord::getUserId)).collect(Collectors.toList()));
+

看下结果

+
[StudentRecord(id=null, userId=11, courseId=100, score=100), StudentRecord(id=null, userId=12, courseId=100, score=100)]
+

但是说实在的这个功能感觉应该是 stream 默认给实现的

+

使用 java.util.stream.Collectors#groupingBy 对 list 进行分组

这个使用场景还是蛮多的,上面的场景里比如我要对 userId 进行分组,就一行代码就解决了

+
System.out.println(list.stream().collect(Collectors.groupingBy(StudentRecord::getUserId)));
+

结果

{11=[StudentRecord(id=null, userId=11, courseId=100, score=100), StudentRecord(id=null, userId=11, courseId=101, score=100)], 12=[StudentRecord(id=null, userId=12, courseId=100, score=100)]}
+

很方便的变成了以 userId 作为 key,以相同 userIdStudentRecordList 作为 valuemap 结构

]]>
- 生活 + java - 生活 - 看剧 + java + stream
- 聊聊最近平淡的生活之看《神探狄仁杰》 - /2021/12/19/%E8%81%8A%E8%81%8A%E6%9C%80%E8%BF%91%E5%B9%B3%E6%B7%A1%E7%9A%84%E7%94%9F%E6%B4%BB%E4%B9%8B%E7%9C%8B%E3%80%8A%E7%A5%9E%E6%8E%A2%E7%8B%84%E4%BB%81%E6%9D%B0%E3%80%8B/ - 其实最近看的不止这一部,前面看了《继承者们》,《少年包青天》这些,就一起聊下,其中看《继承者们》算是个人比较喜欢,以前就有这种看剧的习惯,这个跟《一生一世》里任嘉伦说自己看《寻秦记》看了几十遍一样,我看喜欢的剧也基本上会看不止五遍,继承者们是有帅哥美女看,而且印象中剧情也挺甜的,一般情况下最好是已经有点遗忘剧情了,因为我个人觉得看剧分两种,无聊了又心情不太好,可以看些这类轻松又看过的剧,可以不完全专心地看剧,另外有心情专心看的时候,可以看一些需要思考,一些探案类的或者烧脑类。
最近看了《神探狄仁杰》,因为跟前面看的《少年包青天》都是这类古装探案剧,正好有些感想,《少年包青天》算是儿时阴影,本来是不太会去看的,正好有一次有机会跟 LD 一起看了会就也觉得比较有意思就看了下去,不得不说,以前的这些剧还是很不错的,包括剧情和演员,第一部一共是 40 集,看的过程中也发现了大概是五个案子,平均八集一个案子,整体节奏还是比较慢的,但是基本每个案子其实都是构思得很巧妙,很久以前看过但是现在基本不太记得剧情了,每个案子在前面几集的时候基本都猜不到犯案逻辑,但是在看了狄仁杰之后,发现两部剧也有比较大的差别,少年包青天相对来说逻辑性会更强一些,个人主观觉得推理的严谨性更高,可能剧本打磨上更将就一下,而狄仁杰因为要提现他的个人强项,不比少年包青天中有公孙策一时瑜亮的情节,狄仁杰中分工明确,李元芳是个武力担当,曾泰是捧哏的,相对来说是狄仁杰在案子里从始至终地推进案情,有些甚至有些玄乎,会有一些跳脱跟不合理,有些像是狄仁杰的奇遇,不过这些想法是私人的观点,并不是想要评孰优孰劣;第二个感受是不知道是不是年代关系,特别是少年包青天,每个案件的大 boss 基本都不是个完全的坏人,甚至都是比较情有可原的可怜人,因为一些特殊原因,而好几个都是包拯身边的人,这一点其实跟狄仁杰里第一个使团惊魂案件比较类似,虎敬晖也是个人物形象比较丰满的角色,不是个标签化的淡薄形象,跟金木兰的感情和反叛行动在最后都说明的缘由,而且也有随着跟狄仁杰一起办案被其影响感化,最终为了救狄仁杰而被金木兰所杀,只是这样金木兰这个角色就会有些偏执和符号化,当然剧本肯定不是能面面俱到,这样的剧本已经比现在很多流量剧的好很多了。还想到了前阵子看的《指环王》中的白袍萨鲁曼在剧中也是个比较单薄的角色,这样的电影彪炳影史也没办法把个个人物都设计得完整有血有肉,或者说这本来也是应该有侧重点,当然其实我也不觉得指环王就是绝对的最好的,因为相对来说故事情节的复杂性等真的不如西游记,只是在 86 版之后的各种乱七八糟的翻牌和乱拍已经让这个真正的王者神话故事有点力不从心,这里边有部西游记后传是个人还比较喜欢的,虽然武打动作比较鬼畜,但是剧情基本是无敌的,在西游的架构上衍生出来这么完整丰富的故事,人物角色也都有各自的出彩点。
说回狄仁杰,在这之前也看过徐克拍的几部狄仁杰的电影版,第一部刘德华拍得相对完成度更高,故事性也可圈可点,后面几部就是剧情拉胯,靠特效拉回来一点分,虽说这个也是所谓的狄仁杰宇宙的构思在里面但是现在来看基本是跟西游那些差不多,完全没有整体性可言,打一枪换一个地方,演员也没有延续性,剧情也是前后跳脱,没什么关联跟承上启下,导致质量层次不一,更不用谈什么狄仁杰宇宙了,不过这个事情也是难说,原因很多,现在资本都是更加趋利的,一些需要更长久时间才能有回报的投资是很难获得资本青睐,所以只能将重心投给选择一些流量明星,而本来应该将资源投给剧本打磨的基本就没了,再深入说也没意义了,社会现状就是这样。
还有一点感想是,以前的剧里的拍摄环境还是比较惨的,看着一些房子,甚至皇宫都是比较破旧的,地面还是石板这种,想想以前的演员的环境再想想现在的,比如成龙说的,以前他拍剧就是啪摔了,问这条有没有过,过了就直接送医院,而不是现在可能手蹭破点皮就大叫,甚至还有饭圈这些破事。

+ 记录下 phpunit 的入门使用方法之setUp和tearDown + /2022/10/23/%E8%AE%B0%E5%BD%95%E4%B8%8B-phpunit-%E7%9A%84%E5%85%A5%E9%97%A8%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95%E4%B9%8BsetUp%E5%92%8CtearDown/ + 可能是太久没写单测了,写个单测发现不符合预期,后来验证下才反应过来
我们来看下demo

+
class RenameTest extends TestCase
+{
+    public function setUp(): void
+    {
+        var_dump("setUp");
+    }
+
+    public function test1()
+    {
+        var_dump("test1");
+        assertEquals(1, 1);
+    }
+
+    public function test2()
+    {
+        var_dump("test2");
+        assertEquals(1, 1);
+    }
+
+    protected function tearDown(): void
+    {
+        var_dump("tearDown");
+    }
+}
+

因为我是想写个重命名的小工具,希望通过setUptearDown做一些文件初始化和清理工作,但是我把两个case的初始化跟清理工作写到了单个setUptearDown中,这样就出现了异常的错误
通过上面的示例代码,可以看到执行结果

+
❯ vendor/bin/phpunit
+PHPUnit 9.5.25 by Sebastian Bergmann and contributors.
+
+.string(5) "setUp"
+string(5) "test1"
+string(8) "tearDown"
+.                                                                  2 / 2 (100%)string(5) "setUp"
+string(5) "test2"
+string(8) "tearDown"
+
+
+Time: 00:00.005, Memory: 6.00 MB
+
+OK (2 tests, 2 assertions)
+

其实就是很简单的会在每个test方法前后都执行setUptearDown

]]>
- 生活 + php - 生活 - 看剧 + php
- 聊聊最近平淡的生活之看看老剧 - /2021/11/21/%E8%81%8A%E8%81%8A%E6%9C%80%E8%BF%91%E5%B9%B3%E6%B7%A1%E7%9A%84%E7%94%9F%E6%B4%BB%E4%B9%8B%E7%9C%8B%E7%9C%8B%E8%80%81%E5%89%A7/ - 最近因为也没什么好看的新剧和综艺所以就看看一些以前看过的老剧,我是个非常念旧的人吧,很多剧都会反反复复地看,一方面之前看过觉得好看的的确是一直记着,还有就是平时工作完了回来就想能放松下,剧情太纠结的,太烧脑的都不喜欢,也就是我常挂在口头的不喜欢看费脑子的剧,跟我不喜欢狼人杀的原因也类似。

-

前面其实是看的太阳的后裔,跟 LD 一起看的,之前其实算是看过一点,但是没有看的很完整,并且很多剧情也忘了,只是这个我我可能看得更少一点,因为最开始的时候觉得男主应该是男二,可能对长得这样的男主并且是这样的人设有点失望,感觉不是特别像个特种兵,但是由于本来也比较火,而且 LD 比较喜欢就从这个开始看了,有两个点是比较想说的

-

韩剧虽然被吐槽的很多,但是很多剧的质量,情节把控还是优于目前非常多国内剧的,相对来说剧情发展的前后承接不是那么硬凹出来的,而且人设都立得住,这个是非常重要的,很多国内剧怎么说呢,就是当爹的看起来就比儿子没大几岁,三四十岁的人去演一个十岁出头的小姑娘,除非容貌异常,比如刘晓庆这种,不然就会觉得导演在把我们观众当傻子。瞬间就没有想看下去的欲望了。

-

再一点就是情节是大众都能接受度比较高的,现在有很多普遍会找一些新奇的视角,比如卖腐,想某某令,两部都叫某某令,这其实是一个点,延伸出去就是跟前面说的一点有点类似,xx 老祖,人看着就二三十,叫 xx 老祖,(喜欢的人轻喷哈)然后名字有一堆,同一个人物一会叫这个名字,一会又叫另一个名字,然后一堆死表情。

-

因为今天有个特殊的事情发生,所以简短的写(shui)一篇了

+ 记录下 zookeeper 集群迁移和易错点 + /2022/05/29/%E8%AE%B0%E5%BD%95%E4%B8%8B-zookeeper-%E9%9B%86%E7%BE%A4%E8%BF%81%E7%A7%BB/ + 前阵子做了zk 的集群升级迁移,大概情况是原来是一个三节点的 zk 集群(最小可用
大概是

+
zk1 192.168.2.1
+zk2 192.168.2.2
+zk3 192.168.2.3
+

在 zoo.cfg 中的配置就是如下

+
server.1=192.168.2.1:2888:3888
+server.2=192.168.2.2:2888:3888
+server.3=192.168.2.3:2888:3888
+

加节点

需要将集群迁移到 192.168.2.4(简称 zk4),192.168.2.5(简称 zk5),192.168.2.6(简称 zk6) 这三台机器上,目前新的这三台机器上是没有 zk 部署的, 我们想要的是数据不丢失,那主要考虑的就是滚动升级,这里我其实犯了几个错误,也特别说明下
首先我们想要新的三台机器加进去,所以我在zk4,zk5,zk6 的配置是这样

+
server.1=192.168.2.1:2888:3888
+server.2=192.168.2.2:2888:3888
+server.3=192.168.2.3:2888:3888
+server.4=192.168.2.4:2888:3888
+server.5=192.168.2.5:2888:3888
+server.6=192.168.2.6:2888:3888
+

这样起来发现状态是该节点没起来,
PS:查看当前节点状态可以通过 ./zkServer.sh status 来查看
第一个问题是我需要一个myid文件,标识我是哪个节点,里面的内容就写 456 这样就行了,并且这个文件的路径应该在配置文件中指定的dataDir=数据目录下
第二个问题是困扰我比较久的,我在按上面的配置启动节点后,发现这几个节点都是没起来的,并且有 FastLeaderElection@xxx - Notification time out: 60000 这个报错,一开始以为是网络不通,端口没开这些原因,检查了下都是通的,结果原因其实跟我之前的一个考虑是相关的,当有六个节点的时候,理论上需要有半数以上的节点可用,集群才会是健康的,但是按我这个方式起来,其实我配置了六个节点,但是其中三个都是不可用的(包括自身节点),那么它自然是没办法正常工作,所以这里其实也需要滚动添加,类似于这样
我的 zk4 的配置应该是这样

+
server.1=192.168.2.1:2888:3888
+server.2=192.168.2.2:2888:3888
+server.3=192.168.2.3:2888:3888
+server.4=192.168.2.4:2888:3888
+

然后 zk5 的配置

+
server.1=192.168.2.1:2888:3888
+server.2=192.168.2.2:2888:3888
+server.3=192.168.2.3:2888:3888
+server.4=192.168.2.4:2888:3888
+server.5=192.168.2.5:2888:3888
+

接着 zk6 的配置就可以是全部了

+
server.1=192.168.2.1:2888:3888
+server.2=192.168.2.2:2888:3888
+server.3=192.168.2.3:2888:3888
+server.4=192.168.2.4:2888:3888
+server.5=192.168.2.5:2888:3888
+server.6=192.168.2.6:2888:3888
+

然后为了集群完全更新,就继续在 zk4zk5 加上其他节点,这样我的 6 节点集群就起来了

+

下节点

这里我踩了另外一个坑,或者说没搞清楚两种方式的差别,

+

第一种

首先说说我没采用的第一种方式,(也是比较合理的)其实上面这个集群有个明显的问题,老集群其实还是各自认了一个三节点的集群,其中 zk3 是主节点,对于 zk1,zk2,zk3 来说它们能看到的就只有这三个节点,对于后三个 zk4,zk5,zk6 节点来说他们能连上其余五个节点,可以认为这是个六节点的集群,那么比较合理的操作应该是在老的三节点上把后面三个也都加进来,即每个节点的配置里 server 都有 6 个,然后我再对老的节点进行下线,这里下线需要注意的比较理想的是下一个节点就要修改配置,挪掉下线的节点后进行一遍重启,比如我知道了集群中的 leader 是在 zk3 上面,那么我先将 zk1 和 zk2 下掉,那么在我将 zk1 下线的之后,我将其他的五个节点都删除 zk1 的配置,然后重启,这样其实不是必须,但相对会可靠些,理论上我也可以在下掉 zk1 和 zk2 之后再修改配置重启其余节点。而当只剩下 zk3,zk4,zk5,zk6 四个节点的集群后,并且每个节点里的配置也只有这四个 server,我再下线 zk3 这个 leader 的时候,就会进行选举,再选出新的 leader,因为刚好是三节点,同样保证了最小可用。

+

第二种

这也是我踩坑的一种方式,就是我没有修改原来三节点的配置,并且我一开始以为可以通过下线 zk1,zk2,zk3(进行选举)的方式完成下线,然后再进行重启,但是这种方式就是我上面说的,原来的三节点里我下掉 zk1 还是能够正常运行,但是我下线 zk2 的时候,这个集群就等于是挂了,小于最小可用了,这样三节点都挂了,而且对于新加入的三个节点来说,又回到了最初起不来一样状态,六节点里只有三节点在线,导致整个集群都挂了,所以对于我这样的操作来说,我需要滚动修改启动,在下线 zk1 的时候就需要把 zk4,zk5,zk6 中的 zk1 移除后重启,当然这样唯一的好处就是可以少重启几个,同样继续下线 zk2 的时候,把 zk2 移除掉再重启,其实在移除 zk1 后修改重启后,在下线 zk2 的时候,集群就会重新选举了,因为 zk2 下线的时候,zk3 还是会一起下线。这个是我们需要特别注意的

]]>
- 生活 + java - 生活 - 看剧 + zookeeper
- 聊聊给亲戚朋友的老电脑重装系统那些事儿 - /2021/05/09/%E8%81%8A%E8%81%8A%E7%BB%99%E4%BA%B2%E6%88%9A%E6%9C%8B%E5%8F%8B%E7%9A%84%E8%80%81%E7%94%B5%E8%84%91%E9%87%8D%E8%A3%85%E7%B3%BB%E7%BB%9F%E9%82%A3%E4%BA%9B%E4%BA%8B%E5%84%BF/ - 前面这个五一回去之前,LD 姐姐跟我说电脑很卡了,想让我重装系统,问了下 LD 可能是那个 09 年买的笔记本,想想有点害怕[捂脸],前年有一次好像让我帮忙装了她同事的一个三星的笔记本,本着一些系统洁癖,所以就从开始找纯净版的 win7 家庭版,因为之前那些本基本都自带 win7 的家庭版,而且把激活码就贴在机器下面,然后从三星官网去找官方驱动,还好这个机型的驱动还在,先做了系统镜像,其实感觉这种情况需要两个 U 盘,一个 U 盘装系统作为安装启动盘,一个放驱动,毕竟不是专业装系统的,然后因为官方驱动需要一个个下载一个个安装,然后驱动文件下载的地方还没标明是 32 位还是 64 位的,结果还被 LD 姐姐催着,一直问好没好,略尴尬,索性还是找个一键安装的

-

这次甚至更夸张,上次还让带回去,我准备好了系统镜像啥的,第二天装,这次直接带了两个老旧笔记本过来说让当天就装好,感觉有点像被当修电脑的使,又说这些电脑其实都不用了的,都是为了她们当医生的要每年看会课,然后只能用电脑浏览器看,结果都在用 360 浏览器,真的是万恶的 360,其实以前对 360 没啥坏印象,毕竟以前也经常用,只是对于这些老电脑,360 全家桶真的就是装了就废了,2G 的内存,开机就开着 360 安全卫士,360 杀毒,有一个还装了腾讯电脑管家,然后腾讯视频跟爱奇艺也开机启动了,然后还打开 360 浏览器看课,就算再好的系统也吃不消这么用,重装了系统,还是这么装这些东西,也是分分钟变卡,可惜他们都没啥这类概念。

-

对于他们要看的课,更搞笑的是,明明在页面上注明了说要使用 IE 浏览器,结果他们都在用 360 浏览器看,但是这个也不能完全怪他们,因为实在是现在的 IE 啥的也有开始不兼容 flash 的配置,需要开启兼容配置,但是只要开启了之后就可以直接用 IE 看,比 360 靠谱很多, 资源占用也比较少,360 估计是基于 chromium 加了很多内置的插件,本身 chromium 也是内存大户,但是说这些其实他们也不懂,总觉得找我免费装下系统能撑一段时间,反正对我来说也应该很简单(他们觉得),实际上开始工作以后,我自己想装个双系统都是上淘宝买别人的服务装的,台式机更是几年没动过系统了,因为要重装一大堆软件,数据备份啥的,还有驱动什么的,分区格式,那些驱动精灵啥的也都是越来越坑,一装就给你带一堆垃圾软件。

-

感悟是,总觉得学计算机的就应该会装系统,会修电脑,之前亲戚还拿着一个完全开不起来的笔记本让我来修,这真的是,我说可以找官方维修的,结果我说我搞不定,她直接觉得是修不好了,直接电脑都懒得拿回去了,后面又一次反复解释了才明白,另外就是 360 全家桶,别说老电脑了,新机器都不太吃得消。

+ 这周末我又在老丈人家打了天小工 + /2020/08/30/%E8%BF%99%E5%91%A8%E6%9C%AB%E6%88%91%E5%8F%88%E5%9C%A8%E8%80%81%E4%B8%88%E4%BA%BA%E5%AE%B6%E6%89%93%E4%BA%86%E5%A4%A9%E5%B0%8F%E5%B7%A5/ + 因为活实在比较多,也不太好叫大工(活比较杂散),相比上一次我跟 LD 俩人晚起了一点,我真的是只要有事,早上就醒的很早,准备八点出发的,六点就醒了,然后想继续睡就一直做梦🤦‍♂️,差不多八点半多到的丈人家,他们应该已经干了有一会了,我们到了以后就分配给我撬地板的活,上次说的那个敲掉柜子的房间里,还铺着质地还不错的木地板,但是也不想要了,得撬掉重新铺。
拿着撬棍和榔头就上楼去干了,浙江这几天的天气,最高温度一般 38、9,楼上那个房间也没风扇,有了也不能用,都是灰尘,撬了两下,我感觉我体内的水就像真气爆发一样变成汗炸了出来,眼睛全被汗糊住了,可能大部分人不太了解地板是怎么铺的,一般是在地面先铺一层混凝土,混凝土中间嵌进去规则的长条木条,然后真正的地板一块块的都是钉在那个木条上,用那种气枪钉和普通的钉子,并且块跟块之前还有一个木头的槽结构相互耦合,然后边缘的一圈在用较薄的木板将整个木地板封边(这些词都是我现造的),边缘的用的钉子会更多,所以那几下真的很用力,而且撬地板,得蹲下起来,如此反复,对于我这个体重快超过身高的中年人来说的确是非常大的挑战,接下来继续撬了几个,已经有种要虚脱晕倒的感觉了,及时去喝水擦了汗,又歇了一会,为啥一上来就这么拼呢,主要是因为那个房间丈人在干活的时候是直接看得到的🤦‍♂️,后来被 LD 一顿教育,本来就是去帮忙的,又不是专业做这个的,急啥。
喝了水之后,又稍稍歇了一会,就开始继续撬了,本来觉得这个地板撬着好像还行,房间不大,没多久就撬完了,撬完之后喝了点饮料(补充点糖分,早餐吃得少,有点低血糖),然后看到 LD 在撬下面的木条了,这个动作开始了那天最大的经验值收集行动,前面说了这个木条一般是跟混凝土一块铺上去的,但是谁也没想到,这个混凝土铺上去的时候竟然处理的这么随意,根本没考虑跟下面的贴合,所以撬木条的时候直接把木条跟木条中间大块大块的混凝土一块撬起来了,想想那重量,于是我这靠蛮力干活的,就用力把木条带着混凝土一块撬了起来,还沾沾自喜,但是发现结果是撬起来一块之后,体力值瞬间归零,上一篇我也提到了,其实干这类活也是很有技巧性的,但是上次的是我没学会,可能需要花时间学的,但是这次是LD 用她的纤细胳膊教会我的,我在撬的时候,屏住一口气,双手用力,起,大概是吃好几口奶的力气都用出来了,但是 LD 在我休息的时候,慢慢悠悠的,先把撬棍挤到木条或者混凝土跟下层的缝里,然后往下垫一小块混凝土碎石,然后轻轻松松的扳两下,就撬开了,亏我高中的时候引以为傲的物理成绩,作为物理课代表,这么浅显易懂的杠杆原理都完全不会用到生活里,后面在用这个技巧撬的过程中,真的觉得自己蠢到家了,当然在明白了用点杠杆原理之后,撬地板的活就变得慢慢悠悠,悠哉悠哉的了(其实还是很热的,披着毛巾擦眼睛)。
上午的活差不多完了,后面就是把撬出来的混凝土和地板条丢下去,地上铺着不用了的被子,然后就是午饭和午休环节了,午饭换了一家快餐,味道非常可以,下午的活就比较单调了,帮忙清理了上去扔下来的混凝土碎块跟木条,然后稍微打扫了下,老丈人就让我们回家了,接着上次说的,还是觉得比跑步啥的消耗大太多了,那汗流的,一口就能喝完一瓶 500 毫升左右的矿泉水。

]]>
生活 + 运动 + 跑步 + 干活 生活 - 装电脑 - 老电脑 - 360 全家桶 - 修电脑的 + 运动 + 减肥 + 跑步 + 干活
- 聊聊这次换车牌及其他 - /2022/02/20/%E8%81%8A%E8%81%8A%E8%BF%99%E6%AC%A1%E6%8D%A2%E8%BD%A6%E7%89%8C%E5%8F%8A%E5%85%B6%E4%BB%96/ - 去年 8 月份运气比较好,摇到了车牌,本来其实应该很早就开始摇的,前面第一次换工作没注意社保断缴了一个月,也是大意失荆州,后面到了 17 年社保满两年了,好像只摇了一次,还是就没摇过,有点忘了,好像是什么原因导致那次也没摇成功,但是后面暂住证就取消了,需要居住证,居住证又要一年及以上的租房合同,并且那会买车以后也不怎么开,住的地方车位还好,但是公司车位一个月要两三千,甚至还是打车上下班比较实惠,所以也没放在心上,后面摇到房以后,也觉得应该准备起来车子,就开始办了居住证,居住证其实还可以用劳动合同,而且办起来也挺快,大概是三四月份开始摇,到 8 月份的某一天收到短信说摇到了,一开始还挺开心,不过心里抱着也不怎么开,也没怎么大放在心上,不过这里有一点就是我把那个照片直接发出去,上面有着我的身份证号,被 LD 说了一顿,以后也应该小心点,但是后面不知道是哪里看了下,说杭州上牌已经需要国六标准的车了,瞬间感觉是空欢喜了,可是有同事说是可以的,我就又打了官方的电话,结果说可以的,要先转籍,然后再做上牌。

-

转籍其实是很方便的,在交警 12123 App 上申请就行了,在转籍以后,需要去实地验车,验车的话,在支付宝-杭州交警生活号里进行预约,找就近的车管所就好,需要准备一些东西,首先是行驶证,机动车登记证书,身份证,居住证,还有车上需要准备的东西是要有三脚架和反光背心,反光背心是最近几个月开始要的,问过之前去验车的只需要三脚架就好了,预约好了的话建议是赶上班时间越早越好,不然过去排队时间要很久,而且人多了以后会很乱,各种插队,而且有很多都是汽车销售,一个销售带着一堆车,我们附近那个进去的小路没一会就堵满车,进去需要先排队,然后扫码,接着交资料,这两个都排着队,如果去晚了就要排很久的队,交完资料才是排队等验车,验车就是打开引擎盖,有人会帮忙拓印发动机车架号,然后验车的会各种检查一下,车里面,还有后备箱,建议车内整理干净点,后备箱不要放杂物,检验完了之后,需要把三脚架跟反光背心放在后备箱盖子上,人在旁边拍个照,然后需要把车牌遮住后再拍个车子的照片,再之后就是去把车牌卸了,这个多吐槽下,那边应该是本来那边师傅帮忙卸车牌,结果他就说是教我们拆,虽然也不算难,但是不排除师傅有在偷懒,完了之后就是把旧车牌交回去,然后需要在手机上(警察叔叔 App)提交各种资料,包括身份证,行驶证,机动车登记证书,提交了之后就等寄车牌过来了。

-

这里面缺失的一个环节就是选号了,选号杭州有两个方式,一种就是根据交管局定期发布的选号号段,可以自定义拼 20 个号,在手机上的交警 12123 App 上可以三个一组的形式提交,如果有没被选走的,就可以预选到这个了,但是这种就是也需要有一定策略,最新出的号段能选中的概率大一点,然后数字全是 8,6 这种的肯定会一早就被选走,然后如果跟我一样可以提前选下尾号,因为尾号数字影响限号,我比较有可能周五回家,所以得避开 5,0 的,第二种就是 50 选一跟以前新车选号一样,就不介绍了。第一种选中了以后可以在前面交还旧车牌的时候填上等着寄过来了,因为我是第一种选中的,第二种也可以在手机上选,也在可以在交还车牌的时候现场选。

-

总体过程其实是 LD 在各种查资料跟帮我跑来跑去,要不是 LD,估计在交管局那边我就懵逼了,各种插队,而且车子开着车子,也不能随便跑,所以建议办这个的时候有个人一起比较好。

+ 重看了下《蛮荒记》说说感受 + /2021/10/10/%E9%87%8D%E7%9C%8B%E4%BA%86%E4%B8%8B%E3%80%8A%E8%9B%AE%E8%8D%92%E8%AE%B0%E3%80%8B%E8%AF%B4%E8%AF%B4%E6%84%9F%E5%8F%97/ + 周末把《蛮荒记》看完了,前面是发现微信读书有《搜神记》和《蛮荒记》,但是《搜神记》看了会发现很多都是跳段了,不知道为啥,貌似也没什么少儿不宜的情节,所以就上网找了原版来看,为什么看这个呢,主要还是高中的时候看过,觉得写得很不错,属于那时候的玄幻小说里的独一档,基于山海经创造了一个半架空的大荒宇宙,五族帝尊,人物名都是听说过的,而且又能契合部分历史,整个故事布局非常宏大,并且情节矛盾埋得很深,这里就不对具体情节作介绍了,只是聊聊对书中的一些人物和情节的看法感受。

+

乌丝兰玛是个贯穿两部,甚至在蛮荒的最后还要再搞事情,极其坚定的自以为是的大 boss,其实除了最后被我们的主人公打败,前面几乎就是无所不能,下了一盘无比巨大的棋,主人公都只是其中一个棋子和意外,但是正如很多反派,一直以来都是背着一个信念,并且这个所谓的信念是比较正义的,只是为了这个正义的信念和目标却做了各种丧尽天良的事情,说起来跟灭霸有点像,为了环保哈哈,相对来说感觉姬远玄也只是个最大牌的工具人,或者说是中间人,深爱的妹妹冰夷也意外被蚩尤怒拿一血。

+

但是中间那个赤霞仙子一定要给烈烟石的心上锁,导致最后认不出来蚩尤,也间接导致了蚩尤被杀,如果不考虑最后情节或者推动故事的需求,这个还是我很讨厌的,有点类似于《驴得水》里那个校长,看着貌似是个正常的,做的事情也是正派,但是其实是害人不浅,即使南阳仙子因此被抛进了火山,那也是有贱人在那挑食,并且赤松子是赤飚怒的儿子,烈烟石跟蚩尤又没这层关系,就很像倚天屠龙记里的灭绝师太和极品家丁里的那个玉德仙坊的院主,后者还好一些,前者几乎就是导致周芷若一生悲剧的始作俑者,自己偏执的善恶观,还要给徒弟灌输如此恶毒的理念和让她立下像紧箍咒似的誓言,在人一生中本来就有很多不能如愿的,又被最亲最尊敬的人下了这样的紧箍咒,人生的不幸也加倍了。

+

似乎习惯了总要有个总结的,想说的应该是我觉得这些剧也好,书也好,我觉得最坏的人可能是大部分人眼中的一些次要人物,或者至少大 boss 才是最坏的人,当然这个坏也不是严格的二分法,只是我觉得最让我觉得负面的人物,这些人可能看起来情景出现的不多,只是说了很少的话,做了很少的事,但是在我看来却做了最大的恶。

]]>
生活 生活 - 换车牌 + 看书
- 聊聊那些加塞狗 - /2021/01/17/%E8%81%8A%E8%81%8A%E9%82%A3%E4%BA%9B%E5%8A%A0%E5%A1%9E%E7%8B%97/ - 今天真的是被气得不轻,情况是碰到一个有 70 多秒的直行红灯,然后直行就排了很长的队,但是左转车道没车,就有好几辆车占着左转车道,准备往直行车道插队加塞,一般这种加塞的,会挑个不太计较的,如果前面一辆不让的话就再等等,我因为赶着回家,就不想让,结果那辆车几次车头直接往里冲,当时怒气值基本已经蓄满了,我真的是分毫都不想让,如果路上都是让着这种人的,那么这种情况只会越来越严重,我理解的这种心态,就赌你怕麻烦,多一事不如少一事,结果就是每次都能顺利插队加塞,其实延伸到我们社会中的种种实质性的排队或者等同于排队的情况,都已经有这种惯有思维,一方面这种不符合规则,可能在严重程度上容易被很多人所忽视,基本上已经被很多人当成是“合理”行为,另一方面,对于这些“微小”的违规行为,本身管理层面也基本没有想要管的意思,就更多的成为了纵容这些行为的导火索,并且大多数人都是想着如果不让,发生点小剐小蹭的要浪费很多时间精力来处理,甚至会觉得会被别人觉得自己太小气等等,诸多内外成本结合起来,会真的去硬刚的可能少之又少了,这样也就让更多的人觉得这种行为是被默许的,再举个非常小的例子,以我们公司疫情期间的盒饭发放为例,有两个比较“有意思”的事情,第一个就是因为疫情,本来是让排队要间隔一米,但是可能除了我比较怕死会跟前面的人保持点距离基本没别人会不挨着前面的人,甚至我跟我前面的人保持点距离,后面的同学会推着我让我上去;第二个是关于拿饭,这么多人排着队拿饭,然后有部分同学,一个人拿好几份,帮组里其他人的都拿了,有些甚至一个人拿十份,假如这个盒饭发放是说明了可以按部门直接全领了那就没啥问题,但是当时的状况是个人排队领自己的那一份,如果一个同学直接帮着组里十几个人都拿了,后面排队的人是什么感受呢,甚至有些是看到队伍排长了,就找队伍里自己认识的比较靠前的人说你帮我也拿一份,其实作为我这个比较按规矩办事的“愣头青”来说,我是比较不能接受这两件小事里的行为的,再往下说可能就有点偏激了,先说到这~

+ 闲聊下乘公交的用户体验 + /2021/02/28/%E9%97%B2%E8%81%8A%E4%B8%8B%E4%B9%98%E5%85%AC%E4%BA%A4%E7%9A%84%E7%94%A8%E6%88%B7%E4%BD%93%E9%AA%8C/ + 新年开工开车来杭州,因为没有车位加限行今天来就没开车来了,从东站做公交回住的地方,这班神奇的车我之前也吐槽过了,有神奇的乘客和神奇的司机,因为基本上这班车是从我毕业就开始乘了,所以也算是比较熟悉了,以前总体感觉不太好的是乘坐时间太长了,不过这个也不能怪车,是我自己住得远(离东站),后来住到了现在的地方,也算是直达,并且 LD 比较喜欢直达的,不爱更快却要换乘的地铁,所以坐的频率比较高,也说过前面那些比较气人的乘客,自己不好好戴口罩,反而联合一起上车的乘客诽谤司机,说他要吃人了要打人了,也正是这个司机比较有意思,上车就让戴好口罩,还给大家讲,哪里哪里又有疫情了,我觉得其实这个司机还是不错的,特殊时期,对于这种公共交通,这样的确是比较负责任的做法,只是说话方式,语气这个因人而异,他也不是来伺候人的,而且这么一大车人,说了一遍不行,再说一遍,三遍以上了,嗓门大一点也属于正常的人的行为。
还是说回今天要说的,今天这位司机我看着跟前面说的那位有点像,因为上车的时候比较暗没看清脸,主要原因是这位司机开车比较猛,比较急,然后车上因为这个时间点,比较多大学开学来的学生,拎着个行李箱,一开始是前面已经都站满了人,后面还有很多空位,因为后面没地方放行李箱,就因为这样前面站着的有几个就在说司机开慢点,结果司机貌似也没听进去,还是我行我素,过了会又有人说司机开稳一点,就在这个人说完没一会,停在红绿灯路口的车里,就有人问有没有垃圾桶,接着又让司机开门,说晕车太严重了,要下车,司机开了门,我望出去两个妹子下了车,好像在路边草丛吐了,前面开门下车的时候就有人说她们第一次来杭州,可能有点责怪司机开的不稳,也影响了杭州交通给新来杭州的人的感受,说完了事情经过,其实我有蛮多感触,对于杭州公交司机,我大概是大一来了没多久,陪室友去文三路买电脑就晕车,下车的时候在公交车站吐了,可能是从大学开始缺乏锻炼,又饮食不规律,更加容易晕车,大部分晕车我觉得都是我自己的原因,有时候是上车前吃太多了,或者早上起太早,没睡好,没吃东西,反正自己也是挺多原因的,说到司机的原因的话,我觉得可能这班车还算好的,最让我难受的还是上下班高峰的时候,因为经过的那条路是比较重要的主干道,路比较老比较窄,并且还有很多人行道,所以经常一脚油门连带着一脚刹车,真的很难受,这种算是我觉得真的是公交体验比较差的一点,但是这一点呢也不能完全怪公交司机,杭州的路政规划是很垃圾,没看错,是垃圾,所以总体结论是公交还行,主要是路政规划就是垃圾,包括这条主干道这么多人行道,并且两边都是老小区,老年人在上班高峰可能要买菜送娃或者其他事情,在通畅的情况下可能只需要六分钟的路程,有时候因为各种原因,半小时都开不完,扯开去一点,杭州的路,核心的高速说封就封,本来是高架可以直接通到城西,结果没造,到了路本已经很拥挤的时候开始来造隧道,各种破坏,隧道接高架的地方,无尽的加塞,对于我这样的小白司机来说真的是太恶心了,所以我一直想说的就是杭州这个地方房价领先基础设施十年,地铁,高架,高速通通不行,地面道路就更不行了。
总结下,其实杭州的真正的公交体验差,应该还是路造成的,对于前面的那两位妹子来说,有可能是她们来自于公交司机都是开的特别稳,并且路况也很好的地方,也或者是我被虐习惯了🤦‍♂️

]]>
生活 - 开车 + 公交 生活 @@ -18131,20 +18366,25 @@ $ 加塞 糟心事 规则 + 公交 + 路政规划 + 基础设施 + 杭州 + 高速
- 聊聊部分公交车的设计bug - /2021/12/05/%E8%81%8A%E8%81%8A%E9%83%A8%E5%88%86%E5%85%AC%E4%BA%A4%E8%BD%A6%E7%9A%84%E8%AE%BE%E8%AE%A1bug/ - 今天惯例坐公交回住的地方,不小心撞了头,原因是我们想坐倒数第二排,然后LD 走在我后面,我就走到最后一排中间等着,但是最后一排是高一截的,等 LD 坐进去以后,我就往前走,结果撞到了车顶的扶手杆子的一端,差点撞昏了去,这里我觉得其实杆子长度应该短一点,不然从最后一排出来,还是有比较大概率因为没注意看而撞到头,特别是没注意看的情况,发力其实会比较大,一头撞上就会像我这样,眼前一黑,又痛得要死。
还有一点就是座位设计了,先来看个图

图里大致画了两条线,因为可能是轮胎还是什么原因,后排中间会有那么大的突起,但是看两条红线可以发现,靠近过道的座位边缘跟地面突起的边缘不是一样宽的,这样导致的结果就是坐着的时候有一个脚没地儿搁,要不就得侧着斜着坐,或者就是一个脚悬空,短程的可能还好,路程远一点还是比较难受的,特别是像我现在这样,大腿外侧有点难受的情况,就会更难受。
虽然说这两个点,基本是屁用没有,但是我也是在自己这个博客说说,也当是个树洞了。

+ 闲话篇-也算碰到了为老不尊和坏人变老了的典型案例 + /2022/05/22/%E9%97%B2%E8%AF%9D%E7%AF%87-%E4%B9%9F%E7%AE%97%E7%A2%B0%E5%88%B0%E4%BA%86%E4%B8%BA%E8%80%81%E4%B8%8D%E5%B0%8A%E5%92%8C%E5%9D%8F%E4%BA%BA%E5%8F%98%E8%80%81%E4%BA%86%E7%9A%84%E5%85%B8%E5%9E%8B%E6%A1%88%E4%BE%8B/ + 在目前的房子也差不多租了四五年了,楼下邻居换了两拨了,我们这栋楼装修了不知道多少次,因为是学区的原因,房子交易的频率还是比较高的,不过比较神奇的我们对门的没换过,而且一直也没什么交集(除了后面说的水管爆裂),就进出的时候偶尔看到应该是住着一对老夫妻,感觉年纪也有个七八十了。

+

对对面这户人家的印象,就是对面的老头子经常是我出门上班去了他回来,看着他颤颤巍巍地走楼梯,我看到了都靠边走,而且有几次还听见好像是他儿子在说他,”年假这么大了,还是少出去吧”,说实话除了这次的事情,之前就有一次水管阀门爆裂了,算是有点交集,那次大概是去年冬天,天气已经很冷了,我们周日下午回来看到楼梯有点湿,但是没什么特别的异常就没怎么注意,到晚上洗完澡,楼下的邻居就来敲门,说我们门外的水表那一直在流水,出门一看真的是懵了,外面水表那在哗哗哗地流水,导致楼梯那就跟水帘洞一样,仔细看看是对面家的水表阀门那在漏水,我只能先用塑料袋包一下,然后大冬天(刚洗完澡)穿着凉拖跑下去找物业保安,走到一楼的时候发现水一直流到一楼了,楼梯上都是水流下来,五楼那是最惨的,感觉门框周边都浸透了,五楼的也是态度比较差的让我一定要把水弄好了,但是前面也说了谁是从对门那户的水表阀那出来的,理论上应该让对面的处理,结果我敲门敲了半天对面都没反应,想着我放着不管也不太好,就去找了物业保安,保安上来看了只能先把总阀关了,我也打电话给维修自来水管的,自来水公司的人过了会也是真的来修了,我那会是挺怕不来修,自来水公司的师傅到了以后拿开一看是对面那户的有个阀门估计是自己换上去的,跟我们这的完全不一样,看上去就比较劣质,师傅也挺气的,大晚上被叫过来,我又尝试着去敲门也还是没人应,也没办法,对面老人家我敲太响到时候出来说我吓到他们啥的,第二天去说也没现场了。

+

前面的这件事是个重要铺垫,前几天 LD 下班后把厨余垃圾套好袋子放在门口,打算等我下班了因为要去做核酸(hz 48 小时核酸)顺便带下去,结果到了七点多,说对面的老太太在那疯狂砸门了,LD 被吓到了不敢开门,老太太在外面一边砸门一边骂,“你们年轻人怎么素质这么差”(他们家也经常在门口放垃圾,我们刚来住的时候在楼梯转角他们就放这个废弃的洗衣机,每次走楼梯带点东西都要小心翼翼地走,不然都过不去,然后我赶紧赶回去,结果她听到我回家了,还特意开门继续骂,“你们年轻人怎么素质这么差,垃圾放在这里”,我说我们刚才放在这,打算待会做核酸的时候去扔掉,结果他们家老头,都已经没了牙齿,在那瞪大眼睛说,“你们早上就放在这了的,”我说是LD 刚才下班了放的,争论了一会,我说这个事情我们门口放了垃圾,这会我就去扔掉了,但是你们家老太太这么砸门总不太好,像之前门口水管爆掉了,我敲了门没人应,我也没要砸门一定把你们叫醒,结果老头老太说我们的水管从来没换过,不可能破的(其实到这,再往后说就没意思了,跟这么不要脸的人说多了也只是瞎扯),一会又回到这个垃圾的问题,那个老头说“你们昨天就放在这里了的”,睁着眼说瞎话可真是 666,感觉不是老太太拦着点他马上就要冲上来揍我了一样,事后我想想,这种情况我大概只能躺地上装死了,当这个事情发生之前我真的快把前面说的事情(水管阀坏了)给忘了,虽然这是理论上不该我来处理,除非是老头老太太请求我帮忙,这事后面我也从没说起过,本来完全没交集,对他们的是怎么样的人也没概念,总觉得年纪大了可能还比较心宽和蔼点,结果没想到就是一典型的坏人变老了,我说你们这么砸门,我老婆都被吓得不敢开门,结果对面老头老太太的儿子也出来了说,“我们就是敲下门,我母亲是机关单位退休的,所以肯定不会敲门很大声的,你老婆觉得吓到了是你们人生观价值观有问题”,听到这话我差点笑出来,连着两个可笑至极的脑残逻辑,无语他妈给无语开门,无语到家了。对门家我们之前有个印象就是因为我们都是顶楼,这边老小区以前都是把前后阳台包进来的,然后社区就来咨询大家的意见是不是统一把包进来的违建拆掉,还特地上来六楼跟他们说,结果对面的老头就说,“我要去住建局投诉你们”,本来这个事情是违法的,但是社区的意思也是征求各位业主的意见,结果感觉是社区上门强拆了一样,为老不尊,坏人变老了的典范了。

]]>
生活 生活 - 公交 - 杭州
@@ -18277,77 +18517,50 @@ $ java - - dubbo - - - - 记录下 Java Stream 的一些高效操作 - /2022/05/15/%E8%AE%B0%E5%BD%95%E4%B8%8B-Java-Lambda-%E7%9A%84%E4%B8%80%E4%BA%9B%E9%AB%98%E6%95%88%E6%93%8D%E4%BD%9C/ - 我们日常在代码里处理一些集合逻辑的时候用到 Stream 其实还挺多的,普通的取值过滤集合一般都是结合 ide 的提示就能搞定了,但是有些不太常用的就在这记录下,争取后面都更新记录下来。

-

自定义 distinctByKey 对结果进行去重

stream 中自带的 distinct 只能对元素进行去重
比如下面代码

-
public static void main(String[] args) {
-        List<Integer> list = new ArrayList<>();
-        list.add(1);
-        list.add(1);
-        list.add(2);
-        list = list.stream().distinct().collect(Collectors.toList());
-        System.out.println(list);
-    }
-

结果就是去了重的

-
[1, 2]
-

但是当我的元素是个复杂对象,我想根据对象里的某个元素进行过滤的时候,就需要用到自定义的 distinctByKey 了,比如下面的想对 userId 进行去重

-
public static void main(String[] args) {
-        List<StudentRecord> list = new ArrayList<>();
-        StudentRecord s1 = new StudentRecord();
-        s1.setUserId(11L);
-        s1.setCourseId(100L);
-        s1.setScore(100);
-        list.add(s1);
-        StudentRecord s2 = new StudentRecord();
-        s2.setUserId(11L);
-        s2.setCourseId(101L);
-        s2.setScore(100);
-        list.add(s2);
-        StudentRecord s3 = new StudentRecord();
-        s3.setUserId(12L);
-        s3.setCourseId(100L);
-        s3.setScore(100);
-        list.add(s3);
-        System.out.println(list.stream().distinct().collect(Collectors.toList()));
-    }
-    @Data
-    static class StudentRecord {
-        Long id;
-        Long userId;
-        Long courseId;
-        Integer score;
-    }
-

结果就是

-
[StudentRecord(id=null, userId=11, courseId=100, score=100), StudentRecord(id=null, userId=11, courseId=101, score=100), StudentRecord(id=null, userId=12, courseId=100, score=100)]
-

因为对象都不一样,所以就没法去重了,这里就需要用

-
public static <T> Predicate<T> distinctByKey(
-            Function<? super T, ?> keyExtractor) {
-
-        Map<Object, Boolean> seen = new ConcurrentHashMap<>();
-        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
-    }
-

然后就可以用它来去重了

-
System.out.println(list.stream().filter(distinctByKey(StudentRecord::getUserId)).collect(Collectors.toList()));
-

看下结果

-
[StudentRecord(id=null, userId=11, courseId=100, score=100), StudentRecord(id=null, userId=12, courseId=100, score=100)]
-

但是说实在的这个功能感觉应该是 stream 默认给实现的

-

使用 java.util.stream.Collectors#groupingBy 对 list 进行分组

这个使用场景还是蛮多的,上面的场景里比如我要对 userId 进行分组,就一行代码就解决了

-
System.out.println(list.stream().collect(Collectors.groupingBy(StudentRecord::getUserId)));
-

结果

{11=[StudentRecord(id=null, userId=11, courseId=100, score=100), StudentRecord(id=null, userId=11, courseId=101, score=100)], 12=[StudentRecord(id=null, userId=12, courseId=100, score=100)]}
-

很方便的变成了以 userId 作为 key,以相同 userIdStudentRecordList 作为 valuemap 结构

+ + dubbo + +
+ + 闲话篇-路遇神逻辑骑车带娃爹 + /2022/05/08/%E9%97%B2%E8%AF%9D%E7%AF%87-%E8%B7%AF%E9%81%87%E7%A5%9E%E9%80%BB%E8%BE%91%E9%AA%91%E8%BD%A6%E5%B8%A6%E5%A8%83%E7%88%B9/ + 周末吃完中饭去买菜,没想到碰到这个神(zhi)奇(zhang)大哥带着两个娃,在非机动车道虽然没有像上班高峰车那么多,但是有送外卖,各种叮咚买菜和普通像我这样骑电驴,骑自行车的人,我的情况可能还特殊点,前面说过电驴买了以后本来网上找到过怎么解除限速的,后面看了下,限速 25 虽然慢,但还是对安全很有好处的,我上下班也不赶这个时间,所以就没解除,其他路上的电瓶车包括这位带娃的大哥可能有不少都不符合国标的限速要求或者解除了限速,这些算是铺垫。

+

那位大哥,骑电瓶车一前一后带着两个娃,在非机动车道靠右边行驶,肉眼估计是在我右前方大概十几米的距离,不知道是小孩不舒服了还是啥,想下来还是就在跟他爹玩耍,我算是比较谨慎骑车的,看到这种情况已经准备好捏刹车了,但是也没想到这个娃这么神,差不多能并排四五辆电瓶车的非机动车道,直接从他爸的车下来跑到了非机动车道的最左边,前面我铺垫了电瓶车 25 码,换算一下大概 1 秒能前进 7 米,我是直接把刹车捏死了,才勉强避免撞上这个小孩,并且当时的情况本来我左后方有另一个大哥是想从我左边超过去,因为我刹车了他也赶紧刹车。

+

现在我们做个假设,假如我刹车不够及时,撞上了这个小孩,会是啥后果呢,小孩人没事还好,即使没事也免不了大吵一架,说我骑车不看前面,然后去医院做检查,负责医药费,如果是有点啥伤了,这事估计是没完了,我是心里一阵后怕。

+

说实话是张口快骂人了,“怎么带小孩的”,结果那大哥竟然还是那套话术,“你们骑车不会慢点的啊,说一下就好了啊,用得着这么说吗”,我是真的被这位的逻辑给打败了,还好是想超我车那大哥刹住车了,他要是刹不住呢,把我撞了我怪谁?这不是追尾事件,是 zhizhang 大哥的小孩鬼探头,下个电瓶车就下车,下来就往另一边跑,我们尽力刹车没撞到这小孩,说他没管好小孩这大哥还觉得自己委屈了?结果我倒是想骂脏话了,结果我左后方的的大哥就跟他说“你这么教小孩教得真好,你真厉害”,果然在中国还是不能好好说话,阴阳怪气才是王道,我前面也说了真的是后怕,为什么我从头到尾都没有说这个小孩不对,我是觉得这个年纪的小孩(估摸着也就五六岁或者再大个一两岁)这种安全意识应该是要父母和学校老师一起教育培养的,在路上不能这么随便乱跑,即使别人撞了他,别人有责任,那小孩的生理伤痛和心理伤害,父母也肯定要心疼的吧,另外对我们来说前面也说了,真的撞到了我们也是很难受的,这个社会里真的是自私自利的人太多了,平时让外卖小哥送爬下楼梯送上来外卖都觉得挺抱歉的,每次的接过来都说谢谢,人家也不容易,换在有些人身上大概会觉得自己花了钱就是大爷,给我送上来是必须的。

]]>
- java + 生活 - java - stream + 生活 + +
+ + 难得的大扫除 + /2022/04/10/%E9%9A%BE%E5%BE%97%E7%9A%84%E5%A4%A7%E6%89%AB%E9%99%A4/ + 因为房东要来续签合同,记得之前她说要来看看,后来一直都没来成,一方面我们没打扫过也不想被看到,小房子东西从搬进来以后越来越多,虽然不是脏乱差,但也觉得有点不满意干净状态,这里不得不感叹房东家的有钱程度,买了房子自己都没进房子看过,买来只是为了个学籍,去年前房东把房子卖给新房东后,我们还是比较担心会要换房子了,这里其实是个我们在乎的优点略大于缺点的小房子,面积比较小,但是交通便利以及上下班通勤,周边配套也还不错,有个比较大的菜市场,虽然不常去,因为不太会挑不会还价,还是主要去附近一公里左右的超市,可以安静地挑菜,但是说实在的菜场的菜还是比超市新鲜一些。
大扫除说实在的住在这边以后就没有一次真正意义上的大扫除,因为平时也有在正常打扫,只有偶尔的厨房煤气灶和厕所专门清理下,平时扫地拖地都有做,但是因为说实在的这房子也比较老了,地板什么的都有明显的老化,表面上的油漆都已经被磨损掉了,一些污渍很难拖干净,而且包括厨房和厕所的瓷砖都是纹路特别多,加上磨损,基本是污渍很多,特别是厨房的,又有油渍,我们搬进来的时候厨房的地就已经不太干净了,还有一点就是虽然不是在乡下的房子,但是旁边有两条主干道,一般只要开着窗没几天就灰尘积起来了,公司的电脑在家两天不到就一层灰,而且有些灰在地上时间久一点就会变成那种棉絮状的,看起来就会觉得更脏,并且地板我们平时就是扫一下,然后拖一下没明显的脏东西跟大灰尘就好了,有一些脏的就很难拖干净。
这次的算是整体的大扫除,把柜子,桌子,茶几台,窗边的灰尘都要擦掉,有一些角落还是有蛮多灰尘,当然特别难受的就是电脑那些接口,线缆上的,都杂糅在一块,如果要全都解开了理顺了还是比较麻烦,并且得断电,所以还是尽力清理,但没有全弄开了(我承认我是在偷懒,这里得说下清理了键盘,键盘之前都是放着用,也没盖住,按键缝里就很容易积灰也很难清理,这次索性直接把键全拔了,但是里面的清理也还是挺麻烦,因为不是平板一块,而且还有小孔,有些缝隙也比较难擦进去,只能慢慢地用牙线棒裹着抹布还有棉签擦一下,然后把键帽用洗手液什么的都擦一下洗洗干净,最后晾干了装好感觉就是一把新键盘了,后面主要是拖地了,这次最神奇的就是这个拖地,本来我就跟 LD 吹牛说拖地我是专业的,从小拖到大,有些地板缝边上的污渍,我又是用力来回拖,再用脚踩着拖,还是能把一些原来以为拖不掉的污渍给拖干净了,但是后来的厨房就比较难,用洗洁精来回拖感觉一点都起不来,可能是污渍积了太久了,一开始都想要放弃了,就打算拖干就好了,后来突然看到旁边有个洗衣服的板刷,结果竟然能刷起来,这样就停不下来了,说累是真的非常累,感觉刷一块瓷砖就要休息一会,但是整体刷完之后就是焕然一新的赶脚,简直太有成就感了。

+]]>
+ + 生活 + + + 生活 + 大扫除 + +
+ + 记录下 redis 的一些使用方法 + /2022/10/30/%E8%AE%B0%E5%BD%95%E4%B8%8B-redis-%E7%9A%84%E4%B8%80%E4%BA%9B%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95/ + 虽然说之前讲解过一些redis源码相关的,但是说实话,redis的各种使用其实有时候有点生疏,或者在一些特定的使用场景中,一些使用方法还是需要学习和记录的

+

获取所有数据

获取list类型的所有元素,可以使用 lrange , 直接用lrange key 0 -1
比如

这里有一些方便的就是可以不用知道长度,直接全返回,或者如果想拿到特定区间的就可以直接指定起止范围,

这样就不用一个个pop出来

+

裁剪list

前面用了lrange取得了一个范围的数据,如果想将数据直接移除,那可以用 ltrim ,

这两个命令就可以从list里取出批量数据,并且能从list里删除这部分数据

+]]>
+ + redis + + + redis
@@ -18436,217 +18649,4 @@ OK (1 t php - - 记录下 redis 的一些使用方法 - /2022/10/30/%E8%AE%B0%E5%BD%95%E4%B8%8B-redis-%E7%9A%84%E4%B8%80%E4%BA%9B%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95/ - 虽然说之前讲解过一些redis源码相关的,但是说实话,redis的各种使用其实有时候有点生疏,或者在一些特定的使用场景中,一些使用方法还是需要学习和记录的

-

获取所有数据

获取list类型的所有元素,可以使用 lrange , 直接用lrange key 0 -1
比如

这里有一些方便的就是可以不用知道长度,直接全返回,或者如果想拿到特定区间的就可以直接指定起止范围,

这样就不用一个个pop出来

-

裁剪list

前面用了lrange取得了一个范围的数据,如果想将数据直接移除,那可以用 ltrim ,

这两个命令就可以从list里取出批量数据,并且能从list里删除这部分数据

-]]>
- - redis - - - redis - -
- - 记录下 zookeeper 集群迁移和易错点 - /2022/05/29/%E8%AE%B0%E5%BD%95%E4%B8%8B-zookeeper-%E9%9B%86%E7%BE%A4%E8%BF%81%E7%A7%BB/ - 前阵子做了zk 的集群升级迁移,大概情况是原来是一个三节点的 zk 集群(最小可用
大概是

-
zk1 192.168.2.1
-zk2 192.168.2.2
-zk3 192.168.2.3
-

在 zoo.cfg 中的配置就是如下

-
server.1=192.168.2.1:2888:3888
-server.2=192.168.2.2:2888:3888
-server.3=192.168.2.3:2888:3888
-

加节点

需要将集群迁移到 192.168.2.4(简称 zk4),192.168.2.5(简称 zk5),192.168.2.6(简称 zk6) 这三台机器上,目前新的这三台机器上是没有 zk 部署的, 我们想要的是数据不丢失,那主要考虑的就是滚动升级,这里我其实犯了几个错误,也特别说明下
首先我们想要新的三台机器加进去,所以我在zk4,zk5,zk6 的配置是这样

-
server.1=192.168.2.1:2888:3888
-server.2=192.168.2.2:2888:3888
-server.3=192.168.2.3:2888:3888
-server.4=192.168.2.4:2888:3888
-server.5=192.168.2.5:2888:3888
-server.6=192.168.2.6:2888:3888
-

这样起来发现状态是该节点没起来,
PS:查看当前节点状态可以通过 ./zkServer.sh status 来查看
第一个问题是我需要一个myid文件,标识我是哪个节点,里面的内容就写 456 这样就行了,并且这个文件的路径应该在配置文件中指定的dataDir=数据目录下
第二个问题是困扰我比较久的,我在按上面的配置启动节点后,发现这几个节点都是没起来的,并且有 FastLeaderElection@xxx - Notification time out: 60000 这个报错,一开始以为是网络不通,端口没开这些原因,检查了下都是通的,结果原因其实跟我之前的一个考虑是相关的,当有六个节点的时候,理论上需要有半数以上的节点可用,集群才会是健康的,但是按我这个方式起来,其实我配置了六个节点,但是其中三个都是不可用的(包括自身节点),那么它自然是没办法正常工作,所以这里其实也需要滚动添加,类似于这样
我的 zk4 的配置应该是这样

-
server.1=192.168.2.1:2888:3888
-server.2=192.168.2.2:2888:3888
-server.3=192.168.2.3:2888:3888
-server.4=192.168.2.4:2888:3888
-

然后 zk5 的配置

-
server.1=192.168.2.1:2888:3888
-server.2=192.168.2.2:2888:3888
-server.3=192.168.2.3:2888:3888
-server.4=192.168.2.4:2888:3888
-server.5=192.168.2.5:2888:3888
-

接着 zk6 的配置就可以是全部了

-
server.1=192.168.2.1:2888:3888
-server.2=192.168.2.2:2888:3888
-server.3=192.168.2.3:2888:3888
-server.4=192.168.2.4:2888:3888
-server.5=192.168.2.5:2888:3888
-server.6=192.168.2.6:2888:3888
-

然后为了集群完全更新,就继续在 zk4zk5 加上其他节点,这样我的 6 节点集群就起来了

-

下节点

这里我踩了另外一个坑,或者说没搞清楚两种方式的差别,

-

第一种

首先说说我没采用的第一种方式,(也是比较合理的)其实上面这个集群有个明显的问题,老集群其实还是各自认了一个三节点的集群,其中 zk3 是主节点,对于 zk1,zk2,zk3 来说它们能看到的就只有这三个节点,对于后三个 zk4,zk5,zk6 节点来说他们能连上其余五个节点,可以认为这是个六节点的集群,那么比较合理的操作应该是在老的三节点上把后面三个也都加进来,即每个节点的配置里 server 都有 6 个,然后我再对老的节点进行下线,这里下线需要注意的比较理想的是下一个节点就要修改配置,挪掉下线的节点后进行一遍重启,比如我知道了集群中的 leader 是在 zk3 上面,那么我先将 zk1 和 zk2 下掉,那么在我将 zk1 下线的之后,我将其他的五个节点都删除 zk1 的配置,然后重启,这样其实不是必须,但相对会可靠些,理论上我也可以在下掉 zk1 和 zk2 之后再修改配置重启其余节点。而当只剩下 zk3,zk4,zk5,zk6 四个节点的集群后,并且每个节点里的配置也只有这四个 server,我再下线 zk3 这个 leader 的时候,就会进行选举,再选出新的 leader,因为刚好是三节点,同样保证了最小可用。

-

第二种

这也是我踩坑的一种方式,就是我没有修改原来三节点的配置,并且我一开始以为可以通过下线 zk1,zk2,zk3(进行选举)的方式完成下线,然后再进行重启,但是这种方式就是我上面说的,原来的三节点里我下掉 zk1 还是能够正常运行,但是我下线 zk2 的时候,这个集群就等于是挂了,小于最小可用了,这样三节点都挂了,而且对于新加入的三个节点来说,又回到了最初起不来一样状态,六节点里只有三节点在线,导致整个集群都挂了,所以对于我这样的操作来说,我需要滚动修改启动,在下线 zk1 的时候就需要把 zk4,zk5,zk6 中的 zk1 移除后重启,当然这样唯一的好处就是可以少重启几个,同样继续下线 zk2 的时候,把 zk2 移除掉再重启,其实在移除 zk1 后修改重启后,在下线 zk2 的时候,集群就会重新选举了,因为 zk2 下线的时候,zk3 还是会一起下线。这个是我们需要特别注意的

-]]>
- - java - - - zookeeper - -
- - 重看了下《蛮荒记》说说感受 - /2021/10/10/%E9%87%8D%E7%9C%8B%E4%BA%86%E4%B8%8B%E3%80%8A%E8%9B%AE%E8%8D%92%E8%AE%B0%E3%80%8B%E8%AF%B4%E8%AF%B4%E6%84%9F%E5%8F%97/ - 周末把《蛮荒记》看完了,前面是发现微信读书有《搜神记》和《蛮荒记》,但是《搜神记》看了会发现很多都是跳段了,不知道为啥,貌似也没什么少儿不宜的情节,所以就上网找了原版来看,为什么看这个呢,主要还是高中的时候看过,觉得写得很不错,属于那时候的玄幻小说里的独一档,基于山海经创造了一个半架空的大荒宇宙,五族帝尊,人物名都是听说过的,而且又能契合部分历史,整个故事布局非常宏大,并且情节矛盾埋得很深,这里就不对具体情节作介绍了,只是聊聊对书中的一些人物和情节的看法感受。

-

乌丝兰玛是个贯穿两部,甚至在蛮荒的最后还要再搞事情,极其坚定的自以为是的大 boss,其实除了最后被我们的主人公打败,前面几乎就是无所不能,下了一盘无比巨大的棋,主人公都只是其中一个棋子和意外,但是正如很多反派,一直以来都是背着一个信念,并且这个所谓的信念是比较正义的,只是为了这个正义的信念和目标却做了各种丧尽天良的事情,说起来跟灭霸有点像,为了环保哈哈,相对来说感觉姬远玄也只是个最大牌的工具人,或者说是中间人,深爱的妹妹冰夷也意外被蚩尤怒拿一血。

-

但是中间那个赤霞仙子一定要给烈烟石的心上锁,导致最后认不出来蚩尤,也间接导致了蚩尤被杀,如果不考虑最后情节或者推动故事的需求,这个还是我很讨厌的,有点类似于《驴得水》里那个校长,看着貌似是个正常的,做的事情也是正派,但是其实是害人不浅,即使南阳仙子因此被抛进了火山,那也是有贱人在那挑食,并且赤松子是赤飚怒的儿子,烈烟石跟蚩尤又没这层关系,就很像倚天屠龙记里的灭绝师太和极品家丁里的那个玉德仙坊的院主,后者还好一些,前者几乎就是导致周芷若一生悲剧的始作俑者,自己偏执的善恶观,还要给徒弟灌输如此恶毒的理念和让她立下像紧箍咒似的誓言,在人一生中本来就有很多不能如愿的,又被最亲最尊敬的人下了这样的紧箍咒,人生的不幸也加倍了。

-

似乎习惯了总要有个总结的,想说的应该是我觉得这些剧也好,书也好,我觉得最坏的人可能是大部分人眼中的一些次要人物,或者至少大 boss 才是最坏的人,当然这个坏也不是严格的二分法,只是我觉得最让我觉得负面的人物,这些人可能看起来情景出现的不多,只是说了很少的话,做了很少的事,但是在我看来却做了最大的恶。

-]]>
- - 生活 - - - 生活 - 看书 - -
- - 这周末我又在老丈人家打了天小工 - /2020/08/30/%E8%BF%99%E5%91%A8%E6%9C%AB%E6%88%91%E5%8F%88%E5%9C%A8%E8%80%81%E4%B8%88%E4%BA%BA%E5%AE%B6%E6%89%93%E4%BA%86%E5%A4%A9%E5%B0%8F%E5%B7%A5/ - 因为活实在比较多,也不太好叫大工(活比较杂散),相比上一次我跟 LD 俩人晚起了一点,我真的是只要有事,早上就醒的很早,准备八点出发的,六点就醒了,然后想继续睡就一直做梦🤦‍♂️,差不多八点半多到的丈人家,他们应该已经干了有一会了,我们到了以后就分配给我撬地板的活,上次说的那个敲掉柜子的房间里,还铺着质地还不错的木地板,但是也不想要了,得撬掉重新铺。
拿着撬棍和榔头就上楼去干了,浙江这几天的天气,最高温度一般 38、9,楼上那个房间也没风扇,有了也不能用,都是灰尘,撬了两下,我感觉我体内的水就像真气爆发一样变成汗炸了出来,眼睛全被汗糊住了,可能大部分人不太了解地板是怎么铺的,一般是在地面先铺一层混凝土,混凝土中间嵌进去规则的长条木条,然后真正的地板一块块的都是钉在那个木条上,用那种气枪钉和普通的钉子,并且块跟块之前还有一个木头的槽结构相互耦合,然后边缘的一圈在用较薄的木板将整个木地板封边(这些词都是我现造的),边缘的用的钉子会更多,所以那几下真的很用力,而且撬地板,得蹲下起来,如此反复,对于我这个体重快超过身高的中年人来说的确是非常大的挑战,接下来继续撬了几个,已经有种要虚脱晕倒的感觉了,及时去喝水擦了汗,又歇了一会,为啥一上来就这么拼呢,主要是因为那个房间丈人在干活的时候是直接看得到的🤦‍♂️,后来被 LD 一顿教育,本来就是去帮忙的,又不是专业做这个的,急啥。
喝了水之后,又稍稍歇了一会,就开始继续撬了,本来觉得这个地板撬着好像还行,房间不大,没多久就撬完了,撬完之后喝了点饮料(补充点糖分,早餐吃得少,有点低血糖),然后看到 LD 在撬下面的木条了,这个动作开始了那天最大的经验值收集行动,前面说了这个木条一般是跟混凝土一块铺上去的,但是谁也没想到,这个混凝土铺上去的时候竟然处理的这么随意,根本没考虑跟下面的贴合,所以撬木条的时候直接把木条跟木条中间大块大块的混凝土一块撬起来了,想想那重量,于是我这靠蛮力干活的,就用力把木条带着混凝土一块撬了起来,还沾沾自喜,但是发现结果是撬起来一块之后,体力值瞬间归零,上一篇我也提到了,其实干这类活也是很有技巧性的,但是上次的是我没学会,可能需要花时间学的,但是这次是LD 用她的纤细胳膊教会我的,我在撬的时候,屏住一口气,双手用力,起,大概是吃好几口奶的力气都用出来了,但是 LD 在我休息的时候,慢慢悠悠的,先把撬棍挤到木条或者混凝土跟下层的缝里,然后往下垫一小块混凝土碎石,然后轻轻松松的扳两下,就撬开了,亏我高中的时候引以为傲的物理成绩,作为物理课代表,这么浅显易懂的杠杆原理都完全不会用到生活里,后面在用这个技巧撬的过程中,真的觉得自己蠢到家了,当然在明白了用点杠杆原理之后,撬地板的活就变得慢慢悠悠,悠哉悠哉的了(其实还是很热的,披着毛巾擦眼睛)。
上午的活差不多完了,后面就是把撬出来的混凝土和地板条丢下去,地上铺着不用了的被子,然后就是午饭和午休环节了,午饭换了一家快餐,味道非常可以,下午的活就比较单调了,帮忙清理了上去扔下来的混凝土碎块跟木条,然后稍微打扫了下,老丈人就让我们回家了,接着上次说的,还是觉得比跑步啥的消耗大太多了,那汗流的,一口就能喝完一瓶 500 毫升左右的矿泉水。

-]]>
- - 生活 - 运动 - 跑步 - 干活 - - - 生活 - 运动 - 减肥 - 跑步 - 干活 - -
- - 记录下 phpunit 的入门使用方法之setUp和tearDown - /2022/10/23/%E8%AE%B0%E5%BD%95%E4%B8%8B-phpunit-%E7%9A%84%E5%85%A5%E9%97%A8%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95%E4%B9%8BsetUp%E5%92%8CtearDown/ - 可能是太久没写单测了,写个单测发现不符合预期,后来验证下才反应过来
我们来看下demo

-
class RenameTest extends TestCase
-{
-    public function setUp(): void
-    {
-        var_dump("setUp");
-    }
-
-    public function test1()
-    {
-        var_dump("test1");
-        assertEquals(1, 1);
-    }
-
-    public function test2()
-    {
-        var_dump("test2");
-        assertEquals(1, 1);
-    }
-
-    protected function tearDown(): void
-    {
-        var_dump("tearDown");
-    }
-}
-

因为我是想写个重命名的小工具,希望通过setUptearDown做一些文件初始化和清理工作,但是我把两个case的初始化跟清理工作写到了单个setUptearDown中,这样就出现了异常的错误
通过上面的示例代码,可以看到执行结果

-
❯ vendor/bin/phpunit
-PHPUnit 9.5.25 by Sebastian Bergmann and contributors.
-
-.string(5) "setUp"
-string(5) "test1"
-string(8) "tearDown"
-.                                                                  2 / 2 (100%)string(5) "setUp"
-string(5) "test2"
-string(8) "tearDown"
-
-
-Time: 00:00.005, Memory: 6.00 MB
-
-OK (2 tests, 2 assertions)
-

其实就是很简单的会在每个test方法前后都执行setUptearDown

-]]>
- - php - - - php - -
- - 闲聊下乘公交的用户体验 - /2021/02/28/%E9%97%B2%E8%81%8A%E4%B8%8B%E4%B9%98%E5%85%AC%E4%BA%A4%E7%9A%84%E7%94%A8%E6%88%B7%E4%BD%93%E9%AA%8C/ - 新年开工开车来杭州,因为没有车位加限行今天来就没开车来了,从东站做公交回住的地方,这班神奇的车我之前也吐槽过了,有神奇的乘客和神奇的司机,因为基本上这班车是从我毕业就开始乘了,所以也算是比较熟悉了,以前总体感觉不太好的是乘坐时间太长了,不过这个也不能怪车,是我自己住得远(离东站),后来住到了现在的地方,也算是直达,并且 LD 比较喜欢直达的,不爱更快却要换乘的地铁,所以坐的频率比较高,也说过前面那些比较气人的乘客,自己不好好戴口罩,反而联合一起上车的乘客诽谤司机,说他要吃人了要打人了,也正是这个司机比较有意思,上车就让戴好口罩,还给大家讲,哪里哪里又有疫情了,我觉得其实这个司机还是不错的,特殊时期,对于这种公共交通,这样的确是比较负责任的做法,只是说话方式,语气这个因人而异,他也不是来伺候人的,而且这么一大车人,说了一遍不行,再说一遍,三遍以上了,嗓门大一点也属于正常的人的行为。
还是说回今天要说的,今天这位司机我看着跟前面说的那位有点像,因为上车的时候比较暗没看清脸,主要原因是这位司机开车比较猛,比较急,然后车上因为这个时间点,比较多大学开学来的学生,拎着个行李箱,一开始是前面已经都站满了人,后面还有很多空位,因为后面没地方放行李箱,就因为这样前面站着的有几个就在说司机开慢点,结果司机貌似也没听进去,还是我行我素,过了会又有人说司机开稳一点,就在这个人说完没一会,停在红绿灯路口的车里,就有人问有没有垃圾桶,接着又让司机开门,说晕车太严重了,要下车,司机开了门,我望出去两个妹子下了车,好像在路边草丛吐了,前面开门下车的时候就有人说她们第一次来杭州,可能有点责怪司机开的不稳,也影响了杭州交通给新来杭州的人的感受,说完了事情经过,其实我有蛮多感触,对于杭州公交司机,我大概是大一来了没多久,陪室友去文三路买电脑就晕车,下车的时候在公交车站吐了,可能是从大学开始缺乏锻炼,又饮食不规律,更加容易晕车,大部分晕车我觉得都是我自己的原因,有时候是上车前吃太多了,或者早上起太早,没睡好,没吃东西,反正自己也是挺多原因的,说到司机的原因的话,我觉得可能这班车还算好的,最让我难受的还是上下班高峰的时候,因为经过的那条路是比较重要的主干道,路比较老比较窄,并且还有很多人行道,所以经常一脚油门连带着一脚刹车,真的很难受,这种算是我觉得真的是公交体验比较差的一点,但是这一点呢也不能完全怪公交司机,杭州的路政规划是很垃圾,没看错,是垃圾,所以总体结论是公交还行,主要是路政规划就是垃圾,包括这条主干道这么多人行道,并且两边都是老小区,老年人在上班高峰可能要买菜送娃或者其他事情,在通畅的情况下可能只需要六分钟的路程,有时候因为各种原因,半小时都开不完,扯开去一点,杭州的路,核心的高速说封就封,本来是高架可以直接通到城西,结果没造,到了路本已经很拥挤的时候开始来造隧道,各种破坏,隧道接高架的地方,无尽的加塞,对于我这样的小白司机来说真的是太恶心了,所以我一直想说的就是杭州这个地方房价领先基础设施十年,地铁,高架,高速通通不行,地面道路就更不行了。
总结下,其实杭州的真正的公交体验差,应该还是路造成的,对于前面的那两位妹子来说,有可能是她们来自于公交司机都是开的特别稳,并且路况也很好的地方,也或者是我被虐习惯了🤦‍♂️

-]]>
- - 生活 - 公交 - - - 生活 - 开车 - 加塞 - 糟心事 - 规则 - 公交 - 路政规划 - 基础设施 - 杭州 - 高速 - -
- - 闲话篇-也算碰到了为老不尊和坏人变老了的典型案例 - /2022/05/22/%E9%97%B2%E8%AF%9D%E7%AF%87-%E4%B9%9F%E7%AE%97%E7%A2%B0%E5%88%B0%E4%BA%86%E4%B8%BA%E8%80%81%E4%B8%8D%E5%B0%8A%E5%92%8C%E5%9D%8F%E4%BA%BA%E5%8F%98%E8%80%81%E4%BA%86%E7%9A%84%E5%85%B8%E5%9E%8B%E6%A1%88%E4%BE%8B/ - 在目前的房子也差不多租了四五年了,楼下邻居换了两拨了,我们这栋楼装修了不知道多少次,因为是学区的原因,房子交易的频率还是比较高的,不过比较神奇的我们对门的没换过,而且一直也没什么交集(除了后面说的水管爆裂),就进出的时候偶尔看到应该是住着一对老夫妻,感觉年纪也有个七八十了。

-

对对面这户人家的印象,就是对面的老头子经常是我出门上班去了他回来,看着他颤颤巍巍地走楼梯,我看到了都靠边走,而且有几次还听见好像是他儿子在说他,”年假这么大了,还是少出去吧”,说实话除了这次的事情,之前就有一次水管阀门爆裂了,算是有点交集,那次大概是去年冬天,天气已经很冷了,我们周日下午回来看到楼梯有点湿,但是没什么特别的异常就没怎么注意,到晚上洗完澡,楼下的邻居就来敲门,说我们门外的水表那一直在流水,出门一看真的是懵了,外面水表那在哗哗哗地流水,导致楼梯那就跟水帘洞一样,仔细看看是对面家的水表阀门那在漏水,我只能先用塑料袋包一下,然后大冬天(刚洗完澡)穿着凉拖跑下去找物业保安,走到一楼的时候发现水一直流到一楼了,楼梯上都是水流下来,五楼那是最惨的,感觉门框周边都浸透了,五楼的也是态度比较差的让我一定要把水弄好了,但是前面也说了谁是从对门那户的水表阀那出来的,理论上应该让对面的处理,结果我敲门敲了半天对面都没反应,想着我放着不管也不太好,就去找了物业保安,保安上来看了只能先把总阀关了,我也打电话给维修自来水管的,自来水公司的人过了会也是真的来修了,我那会是挺怕不来修,自来水公司的师傅到了以后拿开一看是对面那户的有个阀门估计是自己换上去的,跟我们这的完全不一样,看上去就比较劣质,师傅也挺气的,大晚上被叫过来,我又尝试着去敲门也还是没人应,也没办法,对面老人家我敲太响到时候出来说我吓到他们啥的,第二天去说也没现场了。

-

前面的这件事是个重要铺垫,前几天 LD 下班后把厨余垃圾套好袋子放在门口,打算等我下班了因为要去做核酸(hz 48 小时核酸)顺便带下去,结果到了七点多,说对面的老太太在那疯狂砸门了,LD 被吓到了不敢开门,老太太在外面一边砸门一边骂,“你们年轻人怎么素质这么差”(他们家也经常在门口放垃圾,我们刚来住的时候在楼梯转角他们就放这个废弃的洗衣机,每次走楼梯带点东西都要小心翼翼地走,不然都过不去,然后我赶紧赶回去,结果她听到我回家了,还特意开门继续骂,“你们年轻人怎么素质这么差,垃圾放在这里”,我说我们刚才放在这,打算待会做核酸的时候去扔掉,结果他们家老头,都已经没了牙齿,在那瞪大眼睛说,“你们早上就放在这了的,”我说是LD 刚才下班了放的,争论了一会,我说这个事情我们门口放了垃圾,这会我就去扔掉了,但是你们家老太太这么砸门总不太好,像之前门口水管爆掉了,我敲了门没人应,我也没要砸门一定把你们叫醒,结果老头老太说我们的水管从来没换过,不可能破的(其实到这,再往后说就没意思了,跟这么不要脸的人说多了也只是瞎扯),一会又回到这个垃圾的问题,那个老头说“你们昨天就放在这里了的”,睁着眼说瞎话可真是 666,感觉不是老太太拦着点他马上就要冲上来揍我了一样,事后我想想,这种情况我大概只能躺地上装死了,当这个事情发生之前我真的快把前面说的事情(水管阀坏了)给忘了,虽然这是理论上不该我来处理,除非是老头老太太请求我帮忙,这事后面我也从没说起过,本来完全没交集,对他们的是怎么样的人也没概念,总觉得年纪大了可能还比较心宽和蔼点,结果没想到就是一典型的坏人变老了,我说你们这么砸门,我老婆都被吓得不敢开门,结果对面老头老太太的儿子也出来了说,“我们就是敲下门,我母亲是机关单位退休的,所以肯定不会敲门很大声的,你老婆觉得吓到了是你们人生观价值观有问题”,听到这话我差点笑出来,连着两个可笑至极的脑残逻辑,无语他妈给无语开门,无语到家了。对门家我们之前有个印象就是因为我们都是顶楼,这边老小区以前都是把前后阳台包进来的,然后社区就来咨询大家的意见是不是统一把包进来的违建拆掉,还特地上来六楼跟他们说,结果对面的老头就说,“我要去住建局投诉你们”,本来这个事情是违法的,但是社区的意思也是征求各位业主的意见,结果感觉是社区上门强拆了一样,为老不尊,坏人变老了的典范了。

-]]>
- - 生活 - - - 生活 - -
- - 闲话篇-路遇神逻辑骑车带娃爹 - /2022/05/08/%E9%97%B2%E8%AF%9D%E7%AF%87-%E8%B7%AF%E9%81%87%E7%A5%9E%E9%80%BB%E8%BE%91%E9%AA%91%E8%BD%A6%E5%B8%A6%E5%A8%83%E7%88%B9/ - 周末吃完中饭去买菜,没想到碰到这个神(zhi)奇(zhang)大哥带着两个娃,在非机动车道虽然没有像上班高峰车那么多,但是有送外卖,各种叮咚买菜和普通像我这样骑电驴,骑自行车的人,我的情况可能还特殊点,前面说过电驴买了以后本来网上找到过怎么解除限速的,后面看了下,限速 25 虽然慢,但还是对安全很有好处的,我上下班也不赶这个时间,所以就没解除,其他路上的电瓶车包括这位带娃的大哥可能有不少都不符合国标的限速要求或者解除了限速,这些算是铺垫。

-

那位大哥,骑电瓶车一前一后带着两个娃,在非机动车道靠右边行驶,肉眼估计是在我右前方大概十几米的距离,不知道是小孩不舒服了还是啥,想下来还是就在跟他爹玩耍,我算是比较谨慎骑车的,看到这种情况已经准备好捏刹车了,但是也没想到这个娃这么神,差不多能并排四五辆电瓶车的非机动车道,直接从他爸的车下来跑到了非机动车道的最左边,前面我铺垫了电瓶车 25 码,换算一下大概 1 秒能前进 7 米,我是直接把刹车捏死了,才勉强避免撞上这个小孩,并且当时的情况本来我左后方有另一个大哥是想从我左边超过去,因为我刹车了他也赶紧刹车。

-

现在我们做个假设,假如我刹车不够及时,撞上了这个小孩,会是啥后果呢,小孩人没事还好,即使没事也免不了大吵一架,说我骑车不看前面,然后去医院做检查,负责医药费,如果是有点啥伤了,这事估计是没完了,我是心里一阵后怕。

-

说实话是张口快骂人了,“怎么带小孩的”,结果那大哥竟然还是那套话术,“你们骑车不会慢点的啊,说一下就好了啊,用得着这么说吗”,我是真的被这位的逻辑给打败了,还好是想超我车那大哥刹住车了,他要是刹不住呢,把我撞了我怪谁?这不是追尾事件,是 zhizhang 大哥的小孩鬼探头,下个电瓶车就下车,下来就往另一边跑,我们尽力刹车没撞到这小孩,说他没管好小孩这大哥还觉得自己委屈了?结果我倒是想骂脏话了,结果我左后方的的大哥就跟他说“你这么教小孩教得真好,你真厉害”,果然在中国还是不能好好说话,阴阳怪气才是王道,我前面也说了真的是后怕,为什么我从头到尾都没有说这个小孩不对,我是觉得这个年纪的小孩(估摸着也就五六岁或者再大个一两岁)这种安全意识应该是要父母和学校老师一起教育培养的,在路上不能这么随便乱跑,即使别人撞了他,别人有责任,那小孩的生理伤痛和心理伤害,父母也肯定要心疼的吧,另外对我们来说前面也说了,真的撞到了我们也是很难受的,这个社会里真的是自私自利的人太多了,平时让外卖小哥送爬下楼梯送上来外卖都觉得挺抱歉的,每次的接过来都说谢谢,人家也不容易,换在有些人身上大概会觉得自己花了钱就是大爷,给我送上来是必须的。

-]]>
- - 生活 - - - 生活 - -
- - 难得的大扫除 - /2022/04/10/%E9%9A%BE%E5%BE%97%E7%9A%84%E5%A4%A7%E6%89%AB%E9%99%A4/ - 因为房东要来续签合同,记得之前她说要来看看,后来一直都没来成,一方面我们没打扫过也不想被看到,小房子东西从搬进来以后越来越多,虽然不是脏乱差,但也觉得有点不满意干净状态,这里不得不感叹房东家的有钱程度,买了房子自己都没进房子看过,买来只是为了个学籍,去年前房东把房子卖给新房东后,我们还是比较担心会要换房子了,这里其实是个我们在乎的优点略大于缺点的小房子,面积比较小,但是交通便利以及上下班通勤,周边配套也还不错,有个比较大的菜市场,虽然不常去,因为不太会挑不会还价,还是主要去附近一公里左右的超市,可以安静地挑菜,但是说实在的菜场的菜还是比超市新鲜一些。
大扫除说实在的住在这边以后就没有一次真正意义上的大扫除,因为平时也有在正常打扫,只有偶尔的厨房煤气灶和厕所专门清理下,平时扫地拖地都有做,但是因为说实在的这房子也比较老了,地板什么的都有明显的老化,表面上的油漆都已经被磨损掉了,一些污渍很难拖干净,而且包括厨房和厕所的瓷砖都是纹路特别多,加上磨损,基本是污渍很多,特别是厨房的,又有油渍,我们搬进来的时候厨房的地就已经不太干净了,还有一点就是虽然不是在乡下的房子,但是旁边有两条主干道,一般只要开着窗没几天就灰尘积起来了,公司的电脑在家两天不到就一层灰,而且有些灰在地上时间久一点就会变成那种棉絮状的,看起来就会觉得更脏,并且地板我们平时就是扫一下,然后拖一下没明显的脏东西跟大灰尘就好了,有一些脏的就很难拖干净。
这次的算是整体的大扫除,把柜子,桌子,茶几台,窗边的灰尘都要擦掉,有一些角落还是有蛮多灰尘,当然特别难受的就是电脑那些接口,线缆上的,都杂糅在一块,如果要全都解开了理顺了还是比较麻烦,并且得断电,所以还是尽力清理,但没有全弄开了(我承认我是在偷懒,这里得说下清理了键盘,键盘之前都是放着用,也没盖住,按键缝里就很容易积灰也很难清理,这次索性直接把键全拔了,但是里面的清理也还是挺麻烦,因为不是平板一块,而且还有小孔,有些缝隙也比较难擦进去,只能慢慢地用牙线棒裹着抹布还有棉签擦一下,然后把键帽用洗手液什么的都擦一下洗洗干净,最后晾干了装好感觉就是一把新键盘了,后面主要是拖地了,这次最神奇的就是这个拖地,本来我就跟 LD 吹牛说拖地我是专业的,从小拖到大,有些地板缝边上的污渍,我又是用力来回拖,再用脚踩着拖,还是能把一些原来以为拖不掉的污渍给拖干净了,但是后来的厨房就比较难,用洗洁精来回拖感觉一点都起不来,可能是污渍积了太久了,一开始都想要放弃了,就打算拖干就好了,后来突然看到旁边有个洗衣服的板刷,结果竟然能刷起来,这样就停不下来了,说累是真的非常累,感觉刷一块瓷砖就要休息一会,但是整体刷完之后就是焕然一新的赶脚,简直太有成就感了。

-]]>
- - 生活 - - - 生活 - 大扫除 - -
diff --git a/sitemap.xml b/sitemap.xml index ea5d22bf7e..a2f4a36653 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -4,7 +4,7 @@ https://nicksxs.me/2023/02/26/%E5%88%86%E4%BA%AB%E4%B8%80%E6%AC%A1%E6%8A%98%E8%85%BE%E8%80%81%E6%97%A7%E7%AC%94%E8%AE%B0%E6%9C%AC%E7%9A%84%E4%BD%93%E9%AA%8C-%E7%BB%AD%E7%BB%AD%E7%AF%87/ - 2023-02-26 + 2023-03-05 monthly 0.6 @@ -443,7 +443,7 @@ - https://nicksxs.me/2021/05/01/Leetcode-48-%E6%97%8B%E8%BD%AC%E5%9B%BE%E5%83%8F-Rotate-Image-%E9%A2%98%E8%A7%A3%E5%88%86%E6%9E%90/ + https://nicksxs.me/2022/03/13/Leetcode-83-%E5%88%A0%E9%99%A4%E6%8E%92%E5%BA%8F%E9%93%BE%E8%A1%A8%E4%B8%AD%E7%9A%84%E9%87%8D%E5%A4%8D%E5%85%83%E7%B4%A0-Remove-Duplicates-from-Sorted-List-Easy-%E9%A2%98%E8%A7%A3%E5%88%86%E6%9E%90/ 2022-06-11 @@ -452,7 +452,7 @@ - https://nicksxs.me/2020/08/06/Linux-%E4%B8%8B-grep-%E5%91%BD%E4%BB%A4%E7%9A%84%E4%B8%80%E7%82%B9%E5%B0%8F%E6%8A%80%E5%B7%A7/ + https://nicksxs.me/2021/05/01/Leetcode-48-%E6%97%8B%E8%BD%AC%E5%9B%BE%E5%83%8F-Rotate-Image-%E9%A2%98%E8%A7%A3%E5%88%86%E6%9E%90/ 2022-06-11 @@ -461,7 +461,7 @@ - https://nicksxs.me/2022/03/13/Leetcode-83-%E5%88%A0%E9%99%A4%E6%8E%92%E5%BA%8F%E9%93%BE%E8%A1%A8%E4%B8%AD%E7%9A%84%E9%87%8D%E5%A4%8D%E5%85%83%E7%B4%A0-Remove-Duplicates-from-Sorted-List-Easy-%E9%A2%98%E8%A7%A3%E5%88%86%E6%9E%90/ + https://nicksxs.me/2020/08/06/Linux-%E4%B8%8B-grep-%E5%91%BD%E4%BB%A4%E7%9A%84%E4%B8%80%E7%82%B9%E5%B0%8F%E6%8A%80%E5%B7%A7/ 2022-06-11 @@ -479,7 +479,7 @@ - https://nicksxs.me/2021/04/18/rust%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/ + https://nicksxs.me/2021/04/18/rust%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0-%E6%89%80%E6%9C%89%E6%9D%83%E4%BA%8C/ 2022-06-11 @@ -488,7 +488,7 @@ - https://nicksxs.me/2021/04/18/rust%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0-%E6%89%80%E6%9C%89%E6%9D%83%E4%BA%8C/ + https://nicksxs.me/2021/04/18/rust%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/ 2022-06-11 @@ -506,7 +506,7 @@ - https://nicksxs.me/2021/12/05/wordpress-%E5%BF%98%E8%AE%B0%E5%AF%86%E7%A0%81%E7%9A%84%E4%B8%80%E7%A7%8D%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95/ + https://nicksxs.me/2021/03/07/%E3%80%8A%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6%E7%AE%97%E6%B3%95%E6%89%8B%E5%86%8C%E8%AF%BB%E4%B9%A6%E3%80%8B%E7%AC%94%E8%AE%B0%E4%B9%8B%E6%95%B4%E7%90%86%E7%AE%97%E6%B3%95/ 2022-06-11 @@ -515,7 +515,7 @@ - https://nicksxs.me/2021/03/07/%E3%80%8A%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6%E7%AE%97%E6%B3%95%E6%89%8B%E5%86%8C%E8%AF%BB%E4%B9%A6%E3%80%8B%E7%AC%94%E8%AE%B0%E4%B9%8B%E6%95%B4%E7%90%86%E7%AE%97%E6%B3%95/ + https://nicksxs.me/2021/12/05/wordpress-%E5%BF%98%E8%AE%B0%E5%AF%86%E7%A0%81%E7%9A%84%E4%B8%80%E7%A7%8D%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95/ 2022-06-11 @@ -587,7 +587,7 @@ - https://nicksxs.me/2021/09/19/%E8%81%8A%E4%B8%80%E4%B8%8B-SpringBoot-%E4%B8%AD%E4%BD%BF%E7%94%A8%E7%9A%84-cglib-%E4%BD%9C%E4%B8%BA%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86%E4%B8%AD%E7%9A%84%E4%B8%80%E4%B8%AA%E6%B3%A8%E6%84%8F%E7%82%B9/ + https://nicksxs.me/2021/09/26/%E8%81%8A%E4%B8%80%E4%B8%8B-SpringBoot-%E4%B8%AD%E5%8A%A8%E6%80%81%E5%88%87%E6%8D%A2%E6%95%B0%E6%8D%AE%E6%BA%90%E7%9A%84%E6%96%B9%E6%B3%95/ 2022-06-11 @@ -596,7 +596,7 @@ - https://nicksxs.me/2021/09/26/%E8%81%8A%E4%B8%80%E4%B8%8B-SpringBoot-%E4%B8%AD%E5%8A%A8%E6%80%81%E5%88%87%E6%8D%A2%E6%95%B0%E6%8D%AE%E6%BA%90%E7%9A%84%E6%96%B9%E6%B3%95/ + https://nicksxs.me/2021/09/19/%E8%81%8A%E4%B8%80%E4%B8%8B-SpringBoot-%E4%B8%AD%E4%BD%BF%E7%94%A8%E7%9A%84-cglib-%E4%BD%9C%E4%B8%BA%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86%E4%B8%AD%E7%9A%84%E4%B8%80%E4%B8%AA%E6%B3%A8%E6%84%8F%E7%82%B9/ 2022-06-11 @@ -614,7 +614,7 @@ - https://nicksxs.me/2021/06/13/%E8%81%8A%E8%81%8A-Java-%E7%9A%84%E7%B1%BB%E5%8A%A0%E8%BD%BD%E6%9C%BA%E5%88%B6%E4%BA%8C/ + https://nicksxs.me/2021/06/27/%E8%81%8A%E8%81%8A-Java-%E4%B8%AD%E7%BB%95%E4%B8%8D%E5%BC%80%E7%9A%84-Synchronized-%E5%85%B3%E9%94%AE%E5%AD%97-%E4%BA%8C/ 2022-06-11 @@ -623,7 +623,7 @@ - https://nicksxs.me/2021/06/27/%E8%81%8A%E8%81%8A-Java-%E4%B8%AD%E7%BB%95%E4%B8%8D%E5%BC%80%E7%9A%84-Synchronized-%E5%85%B3%E9%94%AE%E5%AD%97-%E4%BA%8C/ + https://nicksxs.me/2020/08/02/%E8%81%8A%E8%81%8A-Java-%E8%87%AA%E5%B8%A6%E7%9A%84%E9%82%A3%E4%BA%9B%E9%80%86%E5%A4%A9%E5%B7%A5%E5%85%B7/ 2022-06-11 @@ -632,7 +632,7 @@ - https://nicksxs.me/2020/08/02/%E8%81%8A%E8%81%8A-Java-%E8%87%AA%E5%B8%A6%E7%9A%84%E9%82%A3%E4%BA%9B%E9%80%86%E5%A4%A9%E5%B7%A5%E5%85%B7/ + https://nicksxs.me/2021/06/13/%E8%81%8A%E8%81%8A-Java-%E7%9A%84%E7%B1%BB%E5%8A%A0%E8%BD%BD%E6%9C%BA%E5%88%B6%E4%BA%8C/ 2022-06-11 @@ -650,7 +650,7 @@ - https://nicksxs.me/2022/01/09/%E8%81%8A%E8%81%8A-Sharding-Jdbc-%E5%88%86%E5%BA%93%E5%88%86%E8%A1%A8%E4%B8%8B%E7%9A%84%E5%88%86%E9%A1%B5%E6%96%B9%E6%A1%88/ + https://nicksxs.me/2021/12/26/%E8%81%8A%E8%81%8A-Sharding-Jdbc-%E7%9A%84%E7%AE%80%E5%8D%95%E5%8E%9F%E7%90%86%E5%88%9D%E7%AF%87/ 2022-06-11 @@ -659,7 +659,7 @@ - https://nicksxs.me/2021/12/12/%E8%81%8A%E8%81%8A-Sharding-Jdbc-%E7%9A%84%E7%AE%80%E5%8D%95%E4%BD%BF%E7%94%A8/ + https://nicksxs.me/2022/01/09/%E8%81%8A%E8%81%8A-Sharding-Jdbc-%E5%88%86%E5%BA%93%E5%88%86%E8%A1%A8%E4%B8%8B%E7%9A%84%E5%88%86%E9%A1%B5%E6%96%B9%E6%A1%88/ 2022-06-11 @@ -668,7 +668,7 @@ - https://nicksxs.me/2021/12/26/%E8%81%8A%E8%81%8A-Sharding-Jdbc-%E7%9A%84%E7%AE%80%E5%8D%95%E5%8E%9F%E7%90%86%E5%88%9D%E7%AF%87/ + https://nicksxs.me/2021/12/12/%E8%81%8A%E8%81%8A-Sharding-Jdbc-%E7%9A%84%E7%AE%80%E5%8D%95%E4%BD%BF%E7%94%A8/ 2022-06-11 @@ -1577,7 +1577,7 @@ - https://nicksxs.me/2019/12/10/Redis-Part-1/ + https://nicksxs.me/2015/03/11/Reverse-Bits/ 2020-01-12 @@ -1586,7 +1586,7 @@ - https://nicksxs.me/2015/03/11/Reverse-Bits/ + https://nicksxs.me/2019/12/10/Redis-Part-1/ 2020-01-12 @@ -1595,7 +1595,7 @@ - https://nicksxs.me/2015/01/14/Two-Sum/ + https://nicksxs.me/2015/03/13/Reverse-Integer/ 2020-01-12 @@ -1604,7 +1604,7 @@ - https://nicksxs.me/2017/05/09/ambari-summary/ + https://nicksxs.me/2015/01/14/Two-Sum/ 2020-01-12 @@ -1613,7 +1613,7 @@ - https://nicksxs.me/2015/03/13/Reverse-Integer/ + https://nicksxs.me/2016/09/29/binary-watch/ 2020-01-12 @@ -1622,7 +1622,7 @@ - https://nicksxs.me/2016/09/29/binary-watch/ + https://nicksxs.me/2017/05/09/ambari-summary/ 2020-01-12 @@ -1694,7 +1694,7 @@ - https://nicksxs.me/categories/index.html + https://nicksxs.me/baidu_verify_Gl8jtoDV4z.html 2020-01-12 @@ -1703,7 +1703,7 @@ - https://nicksxs.me/baidu_verify_Gl8jtoDV4z.html + https://nicksxs.me/categories/index.html 2020-01-12 @@ -1748,7 +1748,7 @@ - https://nicksxs.me/2015/01/04/Path-Sum/ + https://nicksxs.me/2015/03/11/Number-Of-1-Bits/ 2020-01-12 @@ -1757,7 +1757,7 @@ - https://nicksxs.me/2015/03/11/Number-Of-1-Bits/ + https://nicksxs.me/2015/01/04/Path-Sum/ 2020-01-12 @@ -1766,7 +1766,7 @@ - https://nicksxs.me/2015/06/22/invert-binary-tree/ + https://nicksxs.me/2014/12/23/my-new-post/ 2020-01-12 @@ -1775,7 +1775,7 @@ - https://nicksxs.me/2014/12/23/my-new-post/ + https://nicksxs.me/2015/06/22/invert-binary-tree/ 2020-01-12 @@ -1867,7 +1867,7 @@ https://nicksxs.me/ - 2023-02-26 + 2023-03-05 daily 1.0 @@ -1875,3082 +1875,3082 @@ https://nicksxs.me/tags/%E7%94%9F%E6%B4%BB/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E5%B9%B4%E7%BB%88%E6%80%BB%E7%BB%93/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/2020/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/2021/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E6%8B%96%E6%9B%B4/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/Java/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/JVM/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/C/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/leetcode/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/java/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/Binary-Tree/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/DFS/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E4%BA%8C%E5%8F%89%E6%A0%91/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E9%A2%98%E8%A7%A3/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/Linked-List/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E8%AF%BB%E5%90%8E%E6%84%9F/ - 2023-02-26 + https://nicksxs.me/tags/%E8%BF%90%E5%8A%A8/ + 2023-03-05 + weekly + 0.2 + + + + https://nicksxs.me/tags/%E5%87%8F%E8%82%A5/ + 2023-03-05 + weekly + 0.2 + + + + https://nicksxs.me/tags/%E8%B7%91%E6%AD%A5/ + 2023-03-05 + weekly + 0.2 + + + + https://nicksxs.me/tags/%E5%B9%B2%E6%B4%BB/ + 2023-03-05 + weekly + 0.2 + + + + https://nicksxs.me/tags/%E5%B0%8F%E6%8A%80%E5%B7%A7/ + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/2019/ - 2023-02-26 + 2023-03-05 + weekly + 0.2 + + + + https://nicksxs.me/tags/%E8%AF%BB%E5%90%8E%E6%84%9F/ + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E5%B9%B4%E4%B8%AD%E6%80%BB%E7%BB%93/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E6%8A%80%E6%9C%AF/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E8%AF%BB%E4%B9%A6/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/c/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E5%B9%B6%E5%8F%91/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/j-u-c/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/aqs/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/condition/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/await/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/signal/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/lock/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/unlock/ - 2023-02-26 - weekly - 0.2 - - - - https://nicksxs.me/tags/2022/ - 2023-02-26 - weekly - 0.2 - - - - https://nicksxs.me/tags/2023/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/Apollo/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/environment/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/value/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E6%B3%A8%E8%A7%A3/ - 2023-02-26 - weekly - 0.2 - - - - https://nicksxs.me/tags/Disruptor/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/Stream/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/Comparator/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E6%8E%92%E5%BA%8F/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/sort/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/nullsfirst/ - 2023-02-26 + 2023-03-05 + weekly + 0.2 + + + + https://nicksxs.me/tags/Disruptor/ + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/Dubbo/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/RPC/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/Filter/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/Interceptor/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/AOP/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/Spring/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/Tomcat/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/Servlet/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/Web/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/G1/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/GC/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/Garbage-First-Collector/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/headscale/ - 2023-02-26 + https://nicksxs.me/tags/2022/ + 2023-03-05 + weekly + 0.2 + + + + https://nicksxs.me/tags/2023/ + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E9%80%92%E5%BD%92/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/Preorder-Traversal/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/Inorder-Traversal/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E5%89%8D%E5%BA%8F/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E4%B8%AD%E5%BA%8F/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/Print-FooBar-Alternately/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/DP/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/Shift-2D-Grid/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/stack/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/min-stack/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E6%9C%80%E5%B0%8F%E6%A0%88/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/leetcode-155/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/3Sum-Closest/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/linked-list/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/First-Bad-Version/ - 2023-02-26 + https://nicksxs.me/tags/Lowest-Common-Ancestor-of-a-Binary-Tree/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/Lowest-Common-Ancestor-of-a-Binary-Tree/ - 2023-02-26 + https://nicksxs.me/tags/string/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/string/ - 2023-02-26 + https://nicksxs.me/tags/First-Bad-Version/ + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/Intersection-of-Two-Arrays/ - 2023-02-26 + 2023-03-05 + weekly + 0.2 + + + + https://nicksxs.me/tags/headscale/ + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/Median-of-Two-Sorted-Arrays/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/dp/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E4%BB%A3%E7%A0%81%E9%A2%98%E8%A7%A3/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/Trapping-Rain-Water/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E6%8E%A5%E9%9B%A8%E6%B0%B4/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/Leetcode-42/ - 2023-02-26 + 2023-03-05 + weekly + 0.2 + + + + https://nicksxs.me/tags/Remove-Duplicates-from-Sorted-List/ + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/Rotate-Image/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E7%9F%A9%E9%98%B5/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/linux/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/grep/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E8%BD%AC%E4%B9%89/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/Remove-Duplicates-from-Sorted-List/ - 2023-02-26 + https://nicksxs.me/tags/mfc/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/mfc/ - 2023-02-26 + https://nicksxs.me/tags/Maven/ + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/C/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/Redis/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/Distributed-Lock/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81/ - 2023-02-26 - weekly - 0.2 - - - - https://nicksxs.me/tags/Maven/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/hadoop/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/cluster/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/docker/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/mysql/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/Docker/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/namespace/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/cgroup/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/Dockerfile/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/echo/ - 2023-02-26 + https://nicksxs.me/tags/Gogs/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/uname/ - 2023-02-26 + https://nicksxs.me/tags/Webhook/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E5%8F%91%E8%A1%8C%E7%89%88/ - 2023-02-26 + https://nicksxs.me/tags/echo/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/Gogs/ - 2023-02-26 + https://nicksxs.me/tags/uname/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/Webhook/ - 2023-02-26 + https://nicksxs.me/tags/%E5%8F%91%E8%A1%8C%E7%89%88/ + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E5%8D%9A%E5%AE%A2%EF%BC%8C%E6%96%87%E7%AB%A0/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/Mysql/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/Mybatis/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E7%BC%93%E5%AD%98/ - 2023-02-26 + https://nicksxs.me/tags/Sql%E6%B3%A8%E5%85%A5/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/Sql%E6%B3%A8%E5%85%A5/ - 2023-02-26 + https://nicksxs.me/tags/%E7%BC%93%E5%AD%98/ + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/nginx/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E6%97%A5%E5%BF%97/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/openresty/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/php/ - 2023-02-26 - weekly - 0.2 - - - - https://nicksxs.me/tags/powershell/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/mq/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/im/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/redis/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E6%BA%90%E7%A0%81/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E6%B7%98%E6%B1%B0%E7%AD%96%E7%95%A5/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E5%BA%94%E7%94%A8/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/Evict/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E8%BF%87%E6%9C%9F%E7%AD%96%E7%95%A5/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/Rust/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E6%89%80%E6%9C%89%E6%9D%83/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E5%86%85%E5%AD%98%E5%88%86%E5%B8%83/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E6%96%B0%E8%AF%AD%E8%A8%80/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E5%8F%AF%E5%8F%98%E5%BC%95%E7%94%A8/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E4%B8%8D%E5%8F%AF%E5%8F%98%E5%BC%95%E7%94%A8/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E5%88%87%E7%89%87/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/spark/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/python/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/Spring-Event/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/websocket/ - 2023-02-26 + https://nicksxs.me/tags/powershell/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/swoole/ - 2023-02-26 + https://nicksxs.me/tags/websocket/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/WordPress/ - 2023-02-26 + https://nicksxs.me/tags/swoole/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E5%B0%8F%E6%8A%80%E5%B7%A7/ - 2023-02-26 + https://nicksxs.me/tags/gc/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/gc/ - 2023-02-26 + https://nicksxs.me/tags/%E6%A0%87%E8%AE%B0%E6%95%B4%E7%90%86/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E6%A0%87%E8%AE%B0%E6%95%B4%E7%90%86/ - 2023-02-26 + https://nicksxs.me/tags/%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6/ - 2023-02-26 + https://nicksxs.me/tags/jvm/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/jvm/ - 2023-02-26 + https://nicksxs.me/tags/WordPress/ + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/MQ/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/RocketMQ/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E5%89%8A%E5%B3%B0%E5%A1%AB%E8%B0%B7/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E4%B8%AD%E9%97%B4%E4%BB%B6/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/ssh/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E7%AB%AF%E5%8F%A3%E8%BD%AC%E5%8F%91/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E5%90%90%E6%A7%BD/ - 2023-02-26 + https://nicksxs.me/tags/%E5%BC%80%E8%BD%A6/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E7%96%AB%E6%83%85/ - 2023-02-26 + https://nicksxs.me/tags/%E5%8A%A0%E5%A1%9E/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E7%BE%8E%E5%9B%BD/ - 2023-02-26 + https://nicksxs.me/tags/%E7%B3%9F%E5%BF%83%E4%BA%8B/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E5%85%AC%E4%BA%A4%E8%BD%A6/ - 2023-02-26 + https://nicksxs.me/tags/%E8%A7%84%E5%88%99/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E5%8F%A3%E7%BD%A9/ - 2023-02-26 + https://nicksxs.me/tags/%E5%85%AC%E4%BA%A4/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E6%9D%80%E4%BA%BA%E8%AF%9B%E5%BF%83/ - 2023-02-26 + https://nicksxs.me/tags/%E8%B7%AF%E6%94%BF%E8%A7%84%E5%88%92/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E6%89%93%E5%8D%A1/ - 2023-02-26 + https://nicksxs.me/tags/%E5%9F%BA%E7%A1%80%E8%AE%BE%E6%96%BD/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E5%B9%B8%E7%A6%8F%E4%BA%86%E5%90%97/ - 2023-02-26 + https://nicksxs.me/tags/%E6%9D%AD%E5%B7%9E/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E8%B6%B3%E7%90%83/ - 2023-02-26 + https://nicksxs.me/tags/%E5%81%A5%E5%BA%B7%E7%A0%81/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E5%BC%80%E8%BD%A6/ - 2023-02-26 + https://nicksxs.me/tags/%E5%90%90%E6%A7%BD/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E5%8A%A0%E5%A1%9E/ - 2023-02-26 + https://nicksxs.me/tags/%E7%96%AB%E6%83%85/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E7%B3%9F%E5%BF%83%E4%BA%8B/ - 2023-02-26 + https://nicksxs.me/tags/%E5%85%AC%E4%BA%A4%E8%BD%A6/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E8%A7%84%E5%88%99/ - 2023-02-26 + https://nicksxs.me/tags/%E5%8F%A3%E7%BD%A9/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E5%85%AC%E4%BA%A4/ - 2023-02-26 + https://nicksxs.me/tags/%E6%9D%80%E4%BA%BA%E8%AF%9B%E5%BF%83/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E8%B7%AF%E6%94%BF%E8%A7%84%E5%88%92/ - 2023-02-26 + https://nicksxs.me/tags/Windows/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E5%9F%BA%E7%A1%80%E8%AE%BE%E6%96%BD/ - 2023-02-26 + https://nicksxs.me/tags/%E6%89%93%E5%8D%A1/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E6%9D%AD%E5%B7%9E/ - 2023-02-26 + https://nicksxs.me/tags/%E5%B9%B8%E7%A6%8F%E4%BA%86%E5%90%97/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E5%81%A5%E5%BA%B7%E7%A0%81/ - 2023-02-26 + https://nicksxs.me/tags/%E8%B6%B3%E7%90%83/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/Windows/ - 2023-02-26 + https://nicksxs.me/tags/git/ + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/scp/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E8%BF%90%E5%8A%A8/ - 2023-02-26 - weekly - 0.2 - - - - https://nicksxs.me/tags/%E5%87%8F%E8%82%A5/ - 2023-02-26 - weekly - 0.2 - - - - https://nicksxs.me/tags/%E8%B7%91%E6%AD%A5/ - 2023-02-26 - weekly - 0.2 - - - - https://nicksxs.me/tags/%E5%B9%B2%E6%B4%BB/ - 2023-02-26 + https://nicksxs.me/tags/%E7%BE%8E%E5%9B%BD/ + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E5%BD%B1%E8%AF%84/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E5%AF%84%E7%94%9F%E8%99%AB/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E5%9B%A4%E7%89%A9%E8%B5%84/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E5%AD%97%E7%AC%A6%E9%9B%86/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E7%BC%96%E7%A0%81/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/utf8/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/utf8mb4/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/utf8mb4-0900-ai-ci/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/utf8mb4-unicode-ci/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/utf8mb4-general-ci/ - 2023-02-26 - weekly - 0.2 - - - - https://nicksxs.me/tags/git/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/DefaultMQPushConsumer/ - 2023-02-26 + https://nicksxs.me/tags/NameServer/ + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/NameServer/ - 2023-02-26 + https://nicksxs.me/tags/DefaultMQPushConsumer/ + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/SpringBoot/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/cglib/ - 2023-02-26 + https://nicksxs.me/tags/Druid/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E4%BA%8B%E5%8A%A1/ - 2023-02-26 + https://nicksxs.me/tags/%E6%95%B0%E6%8D%AE%E6%BA%90%E5%8A%A8%E6%80%81%E5%88%87%E6%8D%A2/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/Druid/ - 2023-02-26 + https://nicksxs.me/tags/%E8%87%AA%E5%8A%A8%E8%A3%85%E9%85%8D/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E6%95%B0%E6%8D%AE%E6%BA%90%E5%8A%A8%E6%80%81%E5%88%87%E6%8D%A2/ - 2023-02-26 + https://nicksxs.me/tags/AutoConfiguration/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E8%87%AA%E5%8A%A8%E8%A3%85%E9%85%8D/ - 2023-02-26 + https://nicksxs.me/tags/cglib/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/AutoConfiguration/ - 2023-02-26 + https://nicksxs.me/tags/%E4%BA%8B%E5%8A%A1/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E4%B8%9C%E4%BA%AC%E5%A5%A5%E8%BF%90%E4%BC%9A/ - 2023-02-26 + https://nicksxs.me/tags/SPI/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E4%B8%BE%E9%87%8D/ - 2023-02-26 + https://nicksxs.me/tags/Adaptive/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E5%B0%84%E5%87%BB/ - 2023-02-26 + https://nicksxs.me/tags/%E8%87%AA%E9%80%82%E5%BA%94%E6%8B%93%E5%B1%95/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E4%B9%92%E4%B9%93%E7%90%83/ - 2023-02-26 + https://nicksxs.me/tags/%E4%B8%9C%E4%BA%AC%E5%A5%A5%E8%BF%90%E4%BC%9A/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E8%B7%B3%E6%B0%B4/ - 2023-02-26 + https://nicksxs.me/tags/%E4%B8%BE%E9%87%8D/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/SPI/ - 2023-02-26 + https://nicksxs.me/tags/%E5%B0%84%E5%87%BB/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/Adaptive/ - 2023-02-26 + https://nicksxs.me/tags/%E4%B9%92%E4%B9%93%E7%90%83/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E8%87%AA%E9%80%82%E5%BA%94%E6%8B%93%E5%B1%95/ - 2023-02-26 + https://nicksxs.me/tags/%E8%B7%B3%E6%B0%B4/ + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E5%AE%B9%E9%94%99%E6%9C%BA%E5%88%B6/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/Synchronized/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E5%81%8F%E5%90%91%E9%94%81/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E8%BD%BB%E9%87%8F%E7%BA%A7%E9%94%81/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E9%87%8D%E9%87%8F%E7%BA%A7%E9%94%81/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E8%87%AA%E6%97%8B/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E7%B1%BB%E5%8A%A0%E8%BD%BD/ - 2023-02-26 + https://nicksxs.me/tags/JPS/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E5%8A%A0%E8%BD%BD/ - 2023-02-26 + https://nicksxs.me/tags/JStack/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E9%AA%8C%E8%AF%81/ - 2023-02-26 + https://nicksxs.me/tags/JMap/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E5%87%86%E5%A4%87/ - 2023-02-26 + https://nicksxs.me/tags/%E7%B1%BB%E5%8A%A0%E8%BD%BD/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E8%A7%A3%E6%9E%90/ - 2023-02-26 + https://nicksxs.me/tags/%E5%8A%A0%E8%BD%BD/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E5%88%9D%E5%A7%8B%E5%8C%96/ - 2023-02-26 + https://nicksxs.me/tags/%E9%AA%8C%E8%AF%81/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E9%93%BE%E6%8E%A5/ - 2023-02-26 + https://nicksxs.me/tags/%E5%87%86%E5%A4%87/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E5%8F%8C%E4%BA%B2%E5%A7%94%E6%B4%BE/ - 2023-02-26 + https://nicksxs.me/tags/%E8%A7%A3%E6%9E%90/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/JPS/ - 2023-02-26 + https://nicksxs.me/tags/%E5%88%9D%E5%A7%8B%E5%8C%96/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/JStack/ - 2023-02-26 + https://nicksxs.me/tags/%E9%93%BE%E6%8E%A5/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/JMap/ - 2023-02-26 + https://nicksxs.me/tags/%E5%8F%8C%E4%BA%B2%E5%A7%94%E6%B4%BE/ + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/top/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/Broker/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/Sharding-Jdbc/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/ThreadPool/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E7%BA%BF%E7%A8%8B%E6%B1%A0/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/FixedThreadPool/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/LimitedThreadPool/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/EagerThreadPool/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/CachedThreadPool/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/mvcc/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/read-view/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/gap-lock/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/next-key-lock/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E5%B9%BB%E8%AF%BB/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E7%B4%A2%E5%BC%95/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/is-null/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/is-not-null/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/procedure/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E7%BC%93%E5%AD%98%E7%A9%BF%E9%80%8F/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E7%BC%93%E5%AD%98%E5%87%BB%E7%A9%BF/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E7%BC%93%E5%AD%98%E9%9B%AA%E5%B4%A9/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E5%B8%83%E9%9A%86%E8%BF%87%E6%BB%A4%E5%99%A8/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/bloom-filter/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E4%BA%92%E6%96%A5%E9%94%81/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/Design-Patterns/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E5%8D%95%E4%BE%8B/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/Singleton/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/Mac/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/PHP/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/Homebrew/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/icu4c/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/zsh/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/ThreadLocal/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E5%BC%B1%E5%BC%95%E7%94%A8/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E5%86%85%E5%AD%98%E6%B3%84%E6%BC%8F/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/WeakReference/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E6%97%85%E6%B8%B8/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E5%8E%A6%E9%97%A8/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E4%B8%AD%E5%B1%B1%E8%B7%AF/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E5%B1%80%E5%8F%A3%E8%A1%97/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E9%BC%93%E6%B5%AA%E5%B1%BF/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E6%9B%BE%E5%8E%9D%E5%9E%B5/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E6%A4%8D%E7%89%A9%E5%9B%AD/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E9%A9%AC%E6%88%8F%E5%9B%A2/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E6%B2%99%E8%8C%B6%E9%9D%A2/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E6%B5%B7%E8%9B%8E%E7%85%8E/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E6%89%B6%E6%A2%AF/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E8%B8%A9%E8%B8%8F/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E5%AE%89%E5%85%A8/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E7%94%B5%E7%93%B6%E8%BD%A6/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/Thread-dump/ - 2023-02-26 + https://nicksxs.me/tags/%E8%BF%9C%E7%A8%8B%E5%8A%9E%E5%85%AC/ + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E5%88%86%E5%B8%83%E5%BC%8F%E4%BA%8B%E5%8A%A1/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E4%B8%A4%E9%98%B6%E6%AE%B5%E6%8F%90%E4%BA%A4/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E4%B8%89%E9%98%B6%E6%AE%B5%E6%8F%90%E4%BA%A4/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/2PC/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/3PC/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E8%BF%9C%E7%A8%8B%E5%8A%9E%E5%85%AC/ - 2023-02-26 + https://nicksxs.me/tags/%E7%9C%8B%E5%89%A7/ + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E9%AA%91%E8%BD%A6/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E7%9C%8B%E5%89%A7/ - 2023-02-26 + https://nicksxs.me/tags/Thread-dump/ + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E8%A3%85%E7%94%B5%E8%84%91/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E8%80%81%E7%94%B5%E8%84%91/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/360-%E5%85%A8%E5%AE%B6%E6%A1%B6/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E4%BF%AE%E7%94%B5%E8%84%91%E7%9A%84/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E6%8D%A2%E8%BD%A6%E7%89%8C/ - 2023-02-26 - weekly - 0.2 - - - - https://nicksxs.me/tags/dubbo/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/stream/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/zookeeper/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E7%9C%8B%E4%B9%A6/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/tags/%E9%AB%98%E9%80%9F/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/tags/%E5%A4%A7%E6%89%AB%E9%99%A4/ - 2023-02-26 + https://nicksxs.me/tags/dubbo/ + 2023-03-05 weekly 0.2 - - - https://nicksxs.me/categories/%E7%94%9F%E6%B4%BB/ - 2023-02-26 + https://nicksxs.me/tags/%E5%A4%A7%E6%89%AB%E9%99%A4/ + 2023-03-05 weekly 0.2 + + - https://nicksxs.me/categories/%E7%94%9F%E6%B4%BB/%E5%B9%B4%E7%BB%88%E6%80%BB%E7%BB%93/ - 2023-02-26 + https://nicksxs.me/categories/%E7%94%9F%E6%B4%BB/ + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/Java/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/%E7%94%9F%E6%B4%BB/%E5%B9%B4%E7%BB%88%E6%80%BB%E7%BB%93/2020/ - 2023-02-26 + https://nicksxs.me/categories/%E7%94%9F%E6%B4%BB/%E5%B9%B4%E7%BB%88%E6%80%BB%E7%BB%93/ + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/Java/JVM/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/leetcode/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Java/leetcode/ - 2023-02-26 + https://nicksxs.me/categories/%E7%94%9F%E6%B4%BB/%E5%B9%B4%E7%BB%88%E6%80%BB%E7%BB%93/2020/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/%E5%B9%B4%E7%BB%88%E6%80%BB%E7%BB%93/ - 2023-02-26 + https://nicksxs.me/categories/Java/leetcode/ + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/Java/GC/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/Binary-Tree/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Linked-List/ - 2023-02-26 + https://nicksxs.me/categories/%E5%B9%B4%E7%BB%88%E6%80%BB%E7%BB%93/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/%E8%AF%BB%E5%90%8E%E6%84%9F/ - 2023-02-26 + https://nicksxs.me/categories/%E7%94%9F%E6%B4%BB/%E5%B9%B4%E7%BB%88%E6%80%BB%E7%BB%93/2019/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/%E5%B9%B4%E7%BB%88%E6%80%BB%E7%BB%93/2020/ - 2023-02-26 + https://nicksxs.me/categories/%E8%AF%BB%E5%90%8E%E6%84%9F/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/%E7%94%9F%E6%B4%BB/%E5%B9%B4%E7%BB%88%E6%80%BB%E7%BB%93/2019/ - 2023-02-26 + https://nicksxs.me/categories/Linked-List/ + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/%E7%94%9F%E6%B4%BB/%E5%B9%B4%E4%B8%AD%E6%80%BB%E7%BB%93/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/C/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/leetcode/java/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Java/%E5%B9%B6%E5%8F%91/ - 2023-02-26 + https://nicksxs.me/categories/%E5%B9%B4%E7%BB%88%E6%80%BB%E7%BB%93/2020/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/%E8%AF%BB%E5%90%8E%E6%84%9F/%E6%9D%91%E4%B8%8A%E6%98%A5%E6%A0%91/ - 2023-02-26 + https://nicksxs.me/categories/Java/%E5%B9%B6%E5%8F%91/ + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/java/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Java/Apollo/ - 2023-02-26 + https://nicksxs.me/categories/%E8%AF%BB%E5%90%8E%E6%84%9F/%E6%9D%91%E4%B8%8A%E6%98%A5%E6%A0%91/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/%E7%94%9F%E6%B4%BB/%E5%B9%B4%E4%B8%AD%E6%80%BB%E7%BB%93/2020/ - 2023-02-26 + https://nicksxs.me/categories/Java/Apollo/ + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/Java/%E9%9B%86%E5%90%88/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Java/Dubbo/ - 2023-02-26 + https://nicksxs.me/categories/%E7%94%9F%E6%B4%BB/%E5%B9%B4%E4%B8%AD%E6%80%BB%E7%BB%93/2020/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/%E7%94%9F%E6%B4%BB/%E5%B9%B4%E4%B8%AD%E6%80%BB%E7%BB%93/2021/ - 2023-02-26 + https://nicksxs.me/categories/Java/Dubbo/ + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/Filter/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/headscale/ - 2023-02-26 + https://nicksxs.me/categories/%E7%94%9F%E6%B4%BB/%E5%B9%B4%E4%B8%AD%E6%80%BB%E7%BB%93/2021/ + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/leetcode/java/Binary-Tree/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/leetcode/java/Linked-List/ - 2023-02-26 + https://nicksxs.me/categories/DP/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/DP/ - 2023-02-26 + https://nicksxs.me/categories/stack/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/stack/ - 2023-02-26 + https://nicksxs.me/categories/Java/Apollo/value/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Java/Apollo/value/ - 2023-02-26 + https://nicksxs.me/categories/leetcode/java/Linked-List/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/linked-list/ - 2023-02-26 + https://nicksxs.me/categories/Java/leetcode/Lowest-Common-Ancestor-of-a-Binary-Tree/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Java/leetcode/Lowest-Common-Ancestor-of-a-Binary-Tree/ - 2023-02-26 + https://nicksxs.me/categories/linked-list/ + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/%E5%AD%97%E7%AC%A6%E4%B8%B2-online/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Java/leetcode/Rotate-Image/ - 2023-02-26 + https://nicksxs.me/categories/headscale/ + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/Interceptor-AOP/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Linux/ - 2023-02-26 + https://nicksxs.me/categories/Java/leetcode/Rotate-Image/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/leetcode/java/Binary-Tree/DFS/ - 2023-02-26 + https://nicksxs.me/categories/Linux/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Redis/ - 2023-02-26 + https://nicksxs.me/categories/leetcode/java/Binary-Tree/DFS/ + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/Java/Maven/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/data-analysis/ - 2023-02-26 + https://nicksxs.me/categories/Redis/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/docker/ - 2023-02-26 + https://nicksxs.me/categories/leetcode/java/DP/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/leetcode/java/DP/ - 2023-02-26 + https://nicksxs.me/categories/data-analysis/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Docker/ - 2023-02-26 + https://nicksxs.me/categories/docker/ + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/leetcode/java/stack/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/%E6%8C%81%E7%BB%AD%E9%9B%86%E6%88%90/ - 2023-02-26 + https://nicksxs.me/categories/Docker/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/leetcode/java/linked-list/ - 2023-02-26 + https://nicksxs.me/categories/%E6%8C%81%E7%BB%AD%E9%9B%86%E6%88%90/ + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/Java/Mybatis/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/leetcode/java/string/ - 2023-02-26 + https://nicksxs.me/categories/leetcode/java/linked-list/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/nginx/ - 2023-02-26 + https://nicksxs.me/categories/leetcode/java/string/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Spring/ - 2023-02-26 + https://nicksxs.me/categories/nginx/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Linux/%E5%91%BD%E4%BB%A4/ - 2023-02-26 + https://nicksxs.me/categories/Spring/ + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/php/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/%E8%AF%AD%E8%A8%80/ - 2023-02-26 + https://nicksxs.me/categories/Linux/%E5%91%BD%E4%BB%A4/ + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/redis/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/Redis/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/Redis/Distributed-Lock/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Docker/%E4%BB%8B%E7%BB%8D/ - 2023-02-26 + https://nicksxs.me/categories/%E8%AF%AD%E8%A8%80/ + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/Java/Spring/ - 2023-02-26 + 2023-03-05 + weekly + 0.2 + + + + https://nicksxs.me/categories/Java/gc/ + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/%E5%B0%8F%E6%8A%80%E5%B7%A7/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Java/gc/ - 2023-02-26 + https://nicksxs.me/categories/Docker/%E4%BB%8B%E7%BB%8D/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/%E7%94%9F%E6%B4%BB/%E8%BF%90%E5%8A%A8/ - 2023-02-26 + https://nicksxs.me/categories/%E8%AF%BB%E5%90%8E%E6%84%9F/%E7%94%9F%E6%B4%BB/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/MQ/ - 2023-02-26 + https://nicksxs.me/categories/%E7%94%9F%E6%B4%BB/%E8%BF%90%E5%8A%A8/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/%E8%AF%BB%E5%90%8E%E6%84%9F/%E7%94%9F%E6%B4%BB/ - 2023-02-26 + https://nicksxs.me/categories/MQ/ + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/ssh/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/%E7%94%9F%E6%B4%BB/%E5%90%90%E6%A7%BD/ - 2023-02-26 + https://nicksxs.me/categories/%E7%94%9F%E6%B4%BB/%E5%85%AC%E4%BA%A4/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/%E8%AF%BB%E5%90%8E%E6%84%9F/%E7%99%BD%E5%B2%A9%E6%9D%BE/ - 2023-02-26 + https://nicksxs.me/categories/%E7%94%9F%E6%B4%BB/%E5%90%90%E6%A7%BD/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/%E7%94%9F%E6%B4%BB/%E5%85%AC%E4%BA%A4/ - 2023-02-26 + https://nicksxs.me/categories/Windows/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Windows/ - 2023-02-26 + https://nicksxs.me/categories/%E8%AF%BB%E5%90%8E%E6%84%9F/%E7%99%BD%E5%B2%A9%E6%9D%BE/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Java/Mybatis/Mysql/ - 2023-02-26 + https://nicksxs.me/categories/git/ + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/shell/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Mybatis/ - 2023-02-26 + https://nicksxs.me/categories/Java/Mybatis/Mysql/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/%E7%94%9F%E6%B4%BB/%E5%BD%B1%E8%AF%84/ - 2023-02-26 + https://nicksxs.me/categories/Mysql/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Mysql/ - 2023-02-26 + https://nicksxs.me/categories/%E7%94%9F%E6%B4%BB/%E5%BD%B1%E8%AF%84/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/git/ - 2023-02-26 + https://nicksxs.me/categories/Mybatis/ + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/Java/SpringBoot/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/Spring/Servlet/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/Java/Dubbo/RPC/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Linux/%E5%91%BD%E4%BB%A4/grep/ - 2023-02-26 + https://nicksxs.me/categories/Dubbo-RPC/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Dubbo-RPC/ - 2023-02-26 + https://nicksxs.me/categories/Java/%E7%B1%BB%E5%8A%A0%E8%BD%BD/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Thread-dump/ - 2023-02-26 + https://nicksxs.me/categories/Linux/%E5%91%BD%E4%BB%A4/grep/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Linux/%E5%91%BD%E4%BB%A4/top/ - 2023-02-26 + https://nicksxs.me/categories/Thread-dump/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Redis/%E6%BA%90%E7%A0%81/ - 2023-02-26 + https://nicksxs.me/categories/Linux/%E5%91%BD%E4%BB%A4/top/ + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/Dubbo-%E7%BA%BF%E7%A8%8B%E6%B1%A0/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/C/ - 2023-02-26 + https://nicksxs.me/categories/Redis/%E5%BA%94%E7%94%A8/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Java/%E7%B1%BB%E5%8A%A0%E8%BD%BD/ - 2023-02-26 + https://nicksxs.me/categories/Java/Design-Patterns/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Redis/%E5%BA%94%E7%94%A8/ - 2023-02-26 + https://nicksxs.me/categories/Mac/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Java/Design-Patterns/ - 2023-02-26 + https://nicksxs.me/categories/Redis/%E6%BA%90%E7%A0%81/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Mac/ - 2023-02-26 + https://nicksxs.me/categories/%E7%94%9F%E6%B4%BB/%E6%97%85%E6%B8%B8/ + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/SpringBoot/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/%E7%94%9F%E6%B4%BB/%E6%97%85%E6%B8%B8/ - 2023-02-26 + https://nicksxs.me/categories/C/ + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/%E5%88%86%E5%B8%83%E5%BC%8F%E4%BA%8B%E5%8A%A1/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/%E7%94%9F%E6%B4%BB/%E5%BC%80%E8%BD%A6/ - 2023-02-26 + https://nicksxs.me/categories/%E8%AF%AD%E8%A8%80/Rust/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/%E8%AF%AD%E8%A8%80/Rust/ - 2023-02-26 + https://nicksxs.me/categories/%E7%94%9F%E6%B4%BB/%E5%BC%80%E8%BD%A6/ + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/Rust/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/Java/gc/jvm/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/MQ/RocketMQ/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/ssh/%E6%8A%80%E5%B7%A7/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Linux/%E5%91%BD%E4%BB%A4/echo/ - 2023-02-26 + https://nicksxs.me/categories/%E7%94%9F%E6%B4%BB/%E5%90%90%E6%A7%BD/%E7%96%AB%E6%83%85/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/%E7%94%9F%E6%B4%BB/%E5%90%90%E6%A7%BD/%E7%96%AB%E6%83%85/ - 2023-02-26 + https://nicksxs.me/categories/Windows/%E5%B0%8F%E6%8A%80%E5%B7%A7/ + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/%E8%AF%BB%E5%90%8E%E6%84%9F/%E7%99%BD%E5%B2%A9%E6%9D%BE/%E5%B9%B8%E7%A6%8F%E4%BA%86%E5%90%97/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Windows/%E5%B0%8F%E6%8A%80%E5%B7%A7/ - 2023-02-26 + https://nicksxs.me/categories/Linux/%E5%91%BD%E4%BB%A4/echo/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/shell/%E5%B0%8F%E6%8A%80%E5%B7%A7/ - 2023-02-26 + https://nicksxs.me/categories/git/%E5%B0%8F%E6%8A%80%E5%B7%A7/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Mybatis/%E7%BC%93%E5%AD%98/ - 2023-02-26 + https://nicksxs.me/categories/shell/%E5%B0%8F%E6%8A%80%E5%B7%A7/ + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/%E7%94%9F%E6%B4%BB/%E8%BF%90%E5%8A%A8/%E8%B7%91%E6%AD%A5/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/%E7%94%9F%E6%B4%BB/%E5%BD%B1%E8%AF%84/2020/ - 2023-02-26 + https://nicksxs.me/categories/Mysql/Sql%E6%B3%A8%E5%85%A5/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Mysql/Sql%E6%B3%A8%E5%85%A5/ - 2023-02-26 + https://nicksxs.me/categories/%E7%94%9F%E6%B4%BB/%E5%BD%B1%E8%AF%84/2020/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/git/%E5%B0%8F%E6%8A%80%E5%B7%A7/ - 2023-02-26 + https://nicksxs.me/categories/Mybatis/%E7%BC%93%E5%AD%98/ + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/Spring/Servlet/Interceptor/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/Java/Dubbo/RPC/SPI/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/%E5%B0%8F%E6%8A%80%E5%B7%A7/grep/ - 2023-02-26 + https://nicksxs.me/categories/Dubbo/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Dubbo/ - 2023-02-26 + https://nicksxs.me/categories/%E5%B0%8F%E6%8A%80%E5%B7%A7/grep/ + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/%E9%97%AE%E9%A2%98%E6%8E%92%E6%9F%A5/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/%E5%B0%8F%E6%8A%80%E5%B7%A7/top/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/Mysql/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/C/Redis/ - 2023-02-26 + https://nicksxs.me/categories/Mysql/%E7%B4%A2%E5%BC%95/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Mysql/%E7%B4%A2%E5%BC%95/ - 2023-02-26 + https://nicksxs.me/categories/Redis/%E7%BC%93%E5%AD%98/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Redis/%E7%BC%93%E5%AD%98/ - 2023-02-26 + https://nicksxs.me/categories/Java/Singleton/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Java/Singleton/ - 2023-02-26 + https://nicksxs.me/categories/Mac/PHP/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Mac/PHP/ - 2023-02-26 + https://nicksxs.me/categories/C/Redis/ + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/%E5%88%86%E5%B8%83%E5%BC%8F%E4%BA%8B%E5%8A%A1/%E4%B8%A4%E9%98%B6%E6%AE%B5%E6%8F%90%E4%BA%A4/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Docker/%E5%8F%91%E8%A1%8C%E7%89%88%E6%9C%AC/ - 2023-02-26 + https://nicksxs.me/categories/%E7%94%9F%E6%B4%BB/%E5%90%90%E6%A7%BD/%E7%96%AB%E6%83%85/%E5%8F%A3%E7%BD%A9/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/%E7%94%9F%E6%B4%BB/%E5%90%90%E6%A7%BD/%E7%96%AB%E6%83%85/%E7%BE%8E%E5%9B%BD/ - 2023-02-26 + https://nicksxs.me/categories/Docker/%E5%8F%91%E8%A1%8C%E7%89%88%E6%9C%AC/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/%E7%94%9F%E6%B4%BB/%E5%90%90%E6%A7%BD/%E7%96%AB%E6%83%85/%E5%8F%A3%E7%BD%A9/ - 2023-02-26 + https://nicksxs.me/categories/%E7%94%9F%E6%B4%BB/%E5%90%90%E6%A7%BD/%E7%96%AB%E6%83%85/%E7%BE%8E%E5%9B%BD/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Spring/Mybatis/ - 2023-02-26 + https://nicksxs.me/categories/%E7%94%9F%E6%B4%BB/%E8%BF%90%E5%8A%A8/%E8%B7%91%E6%AD%A5/%E5%B9%B2%E6%B4%BB/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/%E7%94%9F%E6%B4%BB/%E8%BF%90%E5%8A%A8/%E8%B7%91%E6%AD%A5/%E5%B9%B2%E6%B4%BB/ - 2023-02-26 + https://nicksxs.me/categories/Spring/Mybatis/ + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/MQ/RocketMQ/%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/Spring/Servlet/Interceptor/AOP/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/%E5%B0%8F%E6%8A%80%E5%B7%A7/grep/%E6%9F%A5%E6%97%A5%E5%BF%97/ - 2023-02-26 + https://nicksxs.me/categories/Dubbo/SPI/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Dubbo/SPI/ - 2023-02-26 + https://nicksxs.me/categories/Dubbo/%E5%AE%B9%E9%94%99%E6%9C%BA%E5%88%B6/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Dubbo/%E5%AE%B9%E9%94%99%E6%9C%BA%E5%88%B6/ - 2023-02-26 + https://nicksxs.me/categories/%E5%B0%8F%E6%8A%80%E5%B7%A7/grep/%E6%9F%A5%E6%97%A5%E5%BF%97/ + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/%E5%B7%A5%E5%85%B7/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/%E5%B0%8F%E6%8A%80%E5%B7%A7/top/%E6%8E%92%E5%BA%8F/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/Mysql/%E6%BA%90%E7%A0%81/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/Dubbo/%E7%BA%BF%E7%A8%8B%E6%B1%A0/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/C/Mysql/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/%E7%BC%93%E5%AD%98/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/Mac/Homebrew/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/%E5%88%86%E5%B8%83%E5%BC%8F%E4%BA%8B%E5%8A%A1/%E4%B8%89%E9%98%B6%E6%AE%B5%E6%8F%90%E4%BA%A4/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97/RocketMQ/ - 2023-02-26 + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Dubbo/%E7%BA%BF%E7%A8%8B%E6%B1%A0/ThreadPool/ - 2023-02-26 + https://nicksxs.me/categories/Dubbo/SPI/Adaptive/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/%E7%BC%93%E5%AD%98/%E7%A9%BF%E9%80%8F/ - 2023-02-26 + https://nicksxs.me/categories/Dubbo/%E7%BA%BF%E7%A8%8B%E6%B1%A0/ThreadPool/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/PHP/ - 2023-02-26 + https://nicksxs.me/categories/%E7%BC%93%E5%AD%98/%E7%A9%BF%E9%80%8F/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/%E4%B8%AD%E9%97%B4%E4%BB%B6/ - 2023-02-26 + https://nicksxs.me/categories/PHP/ + 2023-03-05 weekly 0.2 - https://nicksxs.me/categories/Dubbo/SPI/Adaptive/ - 2023-02-26 + https://nicksxs.me/categories/%E4%B8%AD%E9%97%B4%E4%BB%B6/ + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/%E7%BC%93%E5%AD%98/%E7%A9%BF%E9%80%8F/%E5%87%BB%E7%A9%BF/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/PHP/icu4c/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/%E4%B8%AD%E9%97%B4%E4%BB%B6/RocketMQ/ - 2023-02-26 + 2023-03-05 weekly 0.2 https://nicksxs.me/categories/%E7%BC%93%E5%AD%98/%E7%A9%BF%E9%80%8F/%E5%87%BB%E7%A9%BF/%E9%9B%AA%E5%B4%A9/ - 2023-02-26 + 2023-03-05 weekly 0.2 diff --git a/tags/java/page/7/index.html b/tags/java/page/7/index.html index 780011d2ef..6521000d61 100644 --- a/tags/java/page/7/index.html +++ b/tags/java/page/7/index.html @@ -1 +1 @@ -标签: Java | Nicksxs's Blog

Nicksxs's Blog

What hurts more, the pain of hard work or the pain of regret?

0%
\ No newline at end of file +标签: java | Nicksxs's Blog

Nicksxs's Blog

What hurts more, the pain of hard work or the pain of regret?

0%
\ No newline at end of file